Class: Roby::ExecutablePlan

Inherits:
Plan show all
Extended by:
Logger::Forward, Logger::Hierarchy
Includes:
ExceptionHandlingObject
Defined in:
lib/roby/executable_plan.rb

Overview

A plan that can be used for execution

While Plan maintains the plan data structure itself, this class provides excution-related services such as exceptions and GC-related methods

Constant Summary

Constants included from GUI::RelationsCanvasPlan

GUI::RelationsCanvasPlan::PLAN_STROKE_WIDTH

Instance Attribute Summary collapse

Attributes inherited from Plan

#active_fault_response_tables, #event_logger, #event_relation_graphs, #free_events, #graph_observer, #local_owner, #null_event_relation_graphs, #null_task_relation_graphs, #plan_services, #structure_checks, #task_events, #task_index, #task_relation_graphs, #tasks, #transactions, #triggers

Attributes included from GUI::RelationsCanvasPlan

#depth, #max_depth

Attributes included from GUI::GraphvizPlan

#depth, #layout_level

Attributes inherited from DistributedObject

#local_owner_id, #owners

Instance Method Summary collapse

Methods included from ExceptionHandlingObject

#add_error, #handle_exception, #pass_exception

Methods inherited from Plan

#[], #add, #add_event_logger, #add_job_action, #add_mission, #add_mission_task, #add_permanent, #add_permanent_event, #add_permanent_task, #add_plan_service, #add_trigger, #added_transaction, #apply_replacement_operations, #apply_triggers_matches, can_gc?, check_failed_missions, #clear!, #compute_subplan_replacement, #compute_useful_free_events, #compute_useful_tasks, #copy_relation_graphs_to, #copy_task_marks, #copy_to, #create_null_relations, #create_relations, #dedupe, #deep_copy, #deep_copy_to, #default_useful_task_graphs, #dup, #each_event_relation_graph, #each_object_in_transaction_stack, #each_relation_graph, #each_task, #each_task_relation_graph, #edit, #empty?, #event_relation_graph_for, #finalize_event, #finalize_task, #find_all_plan_services, #find_local_tasks, #find_plan_difference, #find_plan_service, #find_tasks, #find_triggers_matches, #force_replace, #force_replace_task, #format_exception_set, #handle_force_replace, #handle_replace, #has_free_event?, #has_task?, #has_task_event?, #in_transaction, #in_useful_subplan?, #include?, #inspect, instanciate_relation_graphs, #local_tasks, #locally_useful_roots, #locally_useful_tasks, #make_useless, #merge, #merge!, #merge_base, #merge_relation_graphs, #merge_transaction!, #mission?, #mission_task?, #mission_tasks, #move_plan_service, #normalize_add_arguments, #notify_event_status_change, #notify_task_status_change, #num_events, #num_free_events, #num_tasks, #owns?, #permanent?, #permanent_event?, #permanent_events, #permanent_task?, #permanent_tasks, #query_result_set, #real_plan, #recreate, #register_event, #register_task, #registered_plan_services_for, #remote_tasks, #remove_fault_response_table, #remove_free_event, #remove_free_event!, #remove_object, #remove_plan_service, #remove_task!, #remove_transaction, #remove_trigger, #replace, #replace_relation_graphs, #replace_subplan, #replace_task, #replaced, #replan, #root_plan?, #same_plan?, #sibling_on?, #size, #static_garbage_collect, #task_relation_graph_for, #template?, #transaction_stack, #unmark_mission, #unmark_mission_task, #unmark_permanent, #unmark_permanent_event, #unmark_permanent_task, #unneeded_events, #unneeded_tasks, #use_fault_response_table, #useful_events, #useful_task?, #useful_tasks, #validate_graphs, #verify_plan_object_finalization_sanity

Methods included from DRoby::V5::PlanDumper

#droby_dump

Methods included from DRoby::Identifiable

#droby_id, #initialize_copy

Methods included from GUI::RelationsCanvasPlan

#display, #display_create, #display_name, #display_parent

Methods included from GUI::GraphvizPlan

#all_events, #apply_layout, #compute_depth, #each_displayed_relation, #each_edge, #each_layout_relation, #layout_relations, #relations_to_dot, #to_dot

Methods included from Roby::EventLogging::Mixin

#log, #log_flush_cycle, #log_queue_size, #log_timepoint, #log_timepoint_group, #log_timepoint_group_end, #log_timepoint_group_start

Methods inherited from DistributedObject

#add_owner, #clear_owners, #initialize_copy, #owned_by?, #remove_owner

Constructor Details

#initializeExecutablePlan

Returns a new instance of ExecutablePlan.



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/roby/executable_plan.rb', line 49

def initialize
    super(graph_observer: self)

    @execution_engine = ExecutionEngine.new(self)
    @quarantined_tasks = Set.new
    @force_gc = Set.new
    @exception_handlers = []
    on_exception LocalizedError do |plan, error|
        plan.default_localized_error_handling(error)
    end
end

Instance Attribute Details

#connection_spaceObject

The ConnectionSpace object which handles this plan. The role of this object is to sharing with other Roby plan managers



21
22
23
# File 'lib/roby/executable_plan.rb', line 21

def connection_space
  @connection_space
end

#exception_handlersArray<(#===, #call)> (readonly)

The list of plan-wide exception handlers

Returns:

  • (Array<(#===, #call)>)


47
48
49
# File 'lib/roby/executable_plan.rb', line 47

def exception_handlers
  @exception_handlers
end

#execution_engineExecutionEngine

The ExecutionEngine object which handles this plan. The role of this object is to provide the event propagation, error propagation and garbage collection mechanisms for the execution.

Returns:



17
18
19
# File 'lib/roby/executable_plan.rb', line 17

def execution_engine
  @execution_engine
end

#force_gcSet<Roby::Task> (readonly)

A set of tasks which are useful (and as such would not been garbage collected), but we want to GC anyway

Returns:



42
43
44
# File 'lib/roby/executable_plan.rb', line 42

def force_gc
  @force_gc
end

#quarantined_tasksSet<Task> (readonly)

Set of running tasks that are in quarantine

Returns:



64
65
66
# File 'lib/roby/executable_plan.rb', line 64

def quarantined_tasks
  @quarantined_tasks
end

Instance Method Details

#added_edge(parent, child, relations, info) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hook called after a new edge has been added in this plan

Parameters:

  • parent (Object)

    the child object

  • child (Object)

    the child object

  • relations (Array<Class<Relations::Graph>>)

    the graphs in which an edge has been added

  • info (Object)

    the associated edge info that applies to relations.first



263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/roby/executable_plan.rb', line 263

def added_edge(parent, child, relations, info)
    relations.each do |rel|
        if rel == Roby::EventStructure::Precedence
            execution_engine.event_ordering.clear
        end

        if (name = rel.child_name)
            parent.send("added_#{name}", child, info)
            child.send("added_#{name}_parent", parent, info)
        end
    end

    log(:added_edge, parent, child, relations, info)
end

#adding_edge(parent, child, relations, info) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hook called before an edge gets added to this plan

If an exception is raised, the edge will not be added

Parameters:

  • parent (Object)

    the child object

  • child (Object)

    the child object

  • relations (Array<Class<Relations::Graph>>)

    the graphs in which an edge has been added

  • info (Object)

    the associated edge info that applies to relations.first



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/roby/executable_plan.rb', line 218

def adding_edge(parent, child, relations, info)
    if !parent.read_write? || !child.read_write?
        raise OwnershipError,
              "cannot remove a relation between two objects we don't own"
    elsif parent.garbage?
        raise ReusingGarbage,
              "attempting to reuse #{parent} which is marked as garbage"
    elsif child.garbage?
        raise ReusingGarbage,
              "attempting to reuse #{child} which is marked as garbage"
    end

    last_dag = relations.find_all(&:dag?).last
    if last_dag && child.relation_graph_for(last_dag).reachable?(child, parent)
        raise Relations::CycleFoundError,
              "adding an edge from #{parent} to #{child} would create "\
              "a cycle in #{last_dag}"
    end

    relations.each do |rel|
        if (name = rel.child_name)
            parent.send("adding_#{name}", child, info)
            child.send("adding_#{name}_parent", parent, info)
        end
    end

    for trsc in transactions
        next unless trsc.proxying?
        next unless (parent_proxy = trsc[parent, create: false])
        next unless (child_proxy = trsc[child, create: false])

        trsc.adding_plan_relation(parent_proxy, child_proxy, relations, info)
    end
end

#call_structure_check_handler(handler) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Called by Roby::ExecutionEngine to verify the plan's internal structure



604
605
606
607
608
# File 'lib/roby/executable_plan.rb', line 604

def call_structure_check_handler(handler)
    super
rescue Exception => e
    execution_engine.add_framework_error(e, "structure checking")
end

#check_quarantined_tasks_in_useObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Look for quarantined tasks that are still in use



155
156
157
158
159
160
161
162
# File 'lib/roby/executable_plan.rb', line 155

def check_quarantined_tasks_in_use
    @quarantined_tasks.each_with_object({}) do |task, result|
        if quarantined_task_in_use?(task)
            error = QuarantinedTaskError.new(task)
            result[error.to_execution_exception] = nil
        end
    end
end

#check_structureObject



148
149
150
# File 'lib/roby/executable_plan.rb', line 148

def check_structure
    super.merge(check_quarantined_tasks_in_use)
end

#clearObject

Clear the plan



586
587
588
589
590
# File 'lib/roby/executable_plan.rb', line 586

def clear
    super
    @force_gc.clear
    @quarantined_tasks.clear
end

#controlObject

The DecisionControl object which is associated with this plan. This object's role is to handle the conflicts that can occur during event propagation.



34
35
36
# File 'lib/roby/executable_plan.rb', line 34

def control
    execution_engine.control
end

#default_localized_error_handling(error) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Default toplevel error handling for LocalizedError

It activates fault handlers, and adds MissionFailedError / PermanentTaskError



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/roby/executable_plan.rb', line 97

def default_localized_error_handling(error)
    matching_handlers = []
    active_fault_response_tables.each do |table|
        table.find_all_matching_handlers(error).each do |handler|
            matching_handlers << [table, handler]
        end
    end
    handlers = matching_handlers.sort_by { |_, handler| handler.priority }

    until handlers.empty?
        table, handler = handlers.shift
        next unless handler

        begin
            handler.activate(error, table.arguments)
            return
        rescue Exception => e
            Robot.warn "ignored exception handler #{handler} "\
                        "because of exception"
            Roby.log_exception_with_backtrace(e, Robot, :warn)
        end
    end

    pass_exception
end

#each_exception_handler {|matcher, handler| ... } ⇒ Object

Iterate over the plan-wide exception handlers

Yield Parameters:



548
549
550
# File 'lib/roby/executable_plan.rb', line 548

def each_exception_handler(&block)
    exception_handlers.each(&block)
end

#emit_relation_change_hook(parent, child, rel, *args, prefix: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper for #updating_edge_info and #updated_edge_info



359
360
361
362
363
364
# File 'lib/roby/executable_plan.rb', line 359

def emit_relation_change_hook(parent, child, rel, *args, prefix: nil)
    if (name = rel.child_name)
        parent.send("#{prefix}_#{name}", child, *args)
        child.send("#{prefix}_#{name}_parent", parent, *args)
    end
end

#emit_relation_graph_merge_hooks(graph, prefix: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Calls the added_* hook methods for all edges in a relation graph

It is a helper for #merged_plan



371
372
373
374
375
376
377
378
379
380
381
# File 'lib/roby/executable_plan.rb', line 371

def emit_relation_graph_merge_hooks(graph, prefix: nil)
    rel = graph.class
    if (name = rel.child_name)
        added_child_hook  = "#{prefix}_#{name}"
        added_parent_hook = "#{added_child_hook}_parent"
        graph.each_edge do |parent, child, info|
            parent.send(added_child_hook, child, info)
            child.send(added_parent_hook, parent, info)
        end
    end
end

#emit_relation_graph_transaction_application_hooks(list, prefix: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Calls the added_ and adding_ hooks for modifications originating from a transaction that involve tasks originally from the plan



387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/roby/executable_plan.rb', line 387

def emit_relation_graph_transaction_application_hooks(list, prefix: nil)
    hooks = {}
    list.each do |graph, parent, child, *args|
        unless hooks.has_key?(graph)
            rel = graph.class
            if (name = rel.child_name)
                parent_hook = "#{prefix}_#{name}"
                child_hook  = "#{parent_hook}_parent"
                hooks[graph] = [parent_hook, child_hook]
            else
                hooks[graph] = nil
            end
        end

        parent_hook, child_hook = hooks[graph]
        next unless child_hook

        parent.send(parent_hook, child, *args)
        child.send(child_hook, parent, *args)
    end
end

#engineObject

Deprecated.

use #execution_engine instead



24
25
26
27
28
29
# File 'lib/roby/executable_plan.rb', line 24

def engine
    Roby.warn_deprecated(
        "Plan#engine is deprecated, use #execution_engine instead"
    )
    execution_engine
end

#executable?Boolean

Check that this is an executable plan

This always returns true for Roby::ExecutablePlan

Returns:

  • (Boolean)


82
83
84
# File 'lib/roby/executable_plan.rb', line 82

def executable?
    true
end

#execute(&block) ⇒ Object

Calls the given block in the execution thread of this plan's engine. If there is no engine attached to this plan, yields immediately

See ExecutionEngine#execute



186
187
188
# File 'lib/roby/executable_plan.rb', line 186

def execute(&block)
    execution_engine.execute(&block)
end

#finalized_event(event) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hook called when an event is finalized



201
202
203
204
# File 'lib/roby/executable_plan.rb', line 201

def finalized_event(event)
    execution_engine.finalized_event(event)
    super
end

#finalized_task(task) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hook called when a task is finalized



193
194
195
196
# File 'lib/roby/executable_plan.rb', line 193

def finalized_task(task)
    execution_engine.finalized_task(task)
    super
end

#garbage_event(event) ⇒ Boolean

Called to handle a free event that should be garbage-collected

What actually happens to the event is controlled by PlanObject#can_finalize?. If the event can be finalized, it is (i.e. removed from the plan, after having triggered all relevant log events/hooks). Otherwise, its relations are cleared and the task is left in the plan

Returns:

  • (Boolean)

    true if the plan got modified, and false otherwise. In practice, it will return false only for events that had no relations and that cannot be finalized.



530
531
532
533
534
535
536
537
538
# File 'lib/roby/executable_plan.rb', line 530

def garbage_event(event)
    log(:garbage_event, droby_id, event)
    if event.can_finalize?
        remove_free_event(event)
        true
    else
        event.clear_relations(remove_strong: false)
    end
end

#garbage_task(task) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Called to handle a task that should be garbage-collected

What actually happens to the task is controlled by PlanObject#can_finalize?.

If the task can be finalized, it is removed from the plan, after having triggered all relevant log events/hooks.

Otherwise, it is isolated from the rest of the plan. Its relations and the relations of its events are cleared and the task is left in the plan. In the latter case, the task is marked as non-reusable.

Always check Task#reusable? before using a task present in an Roby::ExecutablePlan in a new structure.

Parameters:

  • task (Task)

    the task that is being garbage-collected

Returns:

  • (Boolean)

    true if the plan got modified, and false otherwise. In practice, it will return false only if the task cannot be finalized and has external relations.



507
508
509
510
511
512
513
514
515
516
517
# File 'lib/roby/executable_plan.rb', line 507

def garbage_task(task)
    log(:garbage_task, droby_id, task, task.can_finalize?)

    if task.can_finalize?
        remove_task(task)
        true
    else
        task.garbage!
        task.clear_relations(remove_internal: false, remove_strong: false)
    end
end

#generate_induced_errors(error_phase_results) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/roby/executable_plan.rb', line 123

def generate_induced_errors(error_phase_results)
    error_phase_results.each_fatal_error do |execution_exception, tasks|
        # MissionFailedError and PermanentTaskError are not propagated,
        # so tasks == [origin] and we should not re-add an error
        if execution_exception.exception.kind_of?(MissionFailedError) ||
           execution_exception.exception.kind_of?(PermanentTaskError)
            next
        end

        tasks.each do |t|
            if mission_task?(t)
                add_error(
                    MissionFailedError.new(t, execution_exception.exception),
                    propagate_through: []
                )
            elsif permanent_task?(t)
                add_error(
                    PermanentTaskError.new(t, execution_exception.exception),
                    propagate_through: []
                )
            end
        end
    end
end

#merge_transaction(transaction, merged_graphs, added, removed, updated) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Applies modification information extracted from a transaction. This is used by Transaction#commit_transaction



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/roby/executable_plan.rb', line 413

def merge_transaction(transaction, merged_graphs, added, removed, updated)
    added.each do |_, parent, child, _|
        if parent.garbage?
            raise ReusingGarbage,
                  "attempting to reuse #{parent} which is marked as garbage"
        elsif child.garbage?
            raise ReusingGarbage,
                  "attempting to reuse #{child} which is marked as garbage"
        end
    end

    emit_relation_graph_transaction_application_hooks(added, prefix: "adding")
    emit_relation_graph_transaction_application_hooks(removed, prefix: "removing")
    emit_relation_graph_transaction_application_hooks(updated, prefix: "updating")

    super

    precedence_graph = event_relation_graph_for(EventStructure::Precedence)
    precedence_edge_count = precedence_graph.num_edges
    emit_relation_graph_transaction_application_hooks(added, prefix: "added")
    if precedence_edge_count != precedence_graph.num_edges
        execution_engine.event_ordering.clear
    end
    emit_relation_graph_transaction_application_hooks(removed, prefix: "removed")
    if precedence_edge_count != precedence_graph.num_edges
        execution_engine.event_ordering.clear
    end
    emit_relation_graph_transaction_application_hooks(updated, prefix: "updated")

    added.each do |graph, parent, child, info|
        log(:added_edge, parent, child, [graph.class], info)
    end
    removed.each do |graph, parent, child|
        log(:removed_edge, parent, child, [graph.class])
    end
    updated.each do |graph, parent, child, info|
        log(:updated_edge_info, parent, child, graph.class, info)
    end
end

#merged_plan(plan) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits the added_* hooks when a plan gets merged in self



469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# File 'lib/roby/executable_plan.rb', line 469

def merged_plan(plan)
    unless plan.event_relation_graph_for(EventStructure::Precedence).empty?
        execution_engine.event_ordering.clear
    end

    plan.each_task_relation_graph do |graph|
        emit_relation_graph_merge_hooks(graph, prefix: "added")
    end
    plan.each_event_relation_graph do |graph|
        emit_relation_graph_merge_hooks(graph, prefix: "added")
    end

    super

    log(:merged_plan, droby_id, plan)
end

#merging_plan(plan) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits the adding_* hooks when a plan gets merged in self



456
457
458
459
460
461
462
463
464
# File 'lib/roby/executable_plan.rb', line 456

def merging_plan(plan)
    plan.each_task_relation_graph do |graph|
        emit_relation_graph_merge_hooks(graph, prefix: "adding")
    end
    plan.each_event_relation_graph do |graph|
        emit_relation_graph_merge_hooks(graph, prefix: "adding")
    end
    super
end

#on_exception(matcher) {|plan, exception| ... } ⇒ Object

Register a new exception handler

Parameters:

  • matcher (#===, #to_execution_exception_matcher)

    an object that matches exceptions for which the handler should be called. Exception classes can be used directly. If more advanced matching is needed, use .match to convert an exception class into Queries::LocalizedErrorMatcher or one of its subclasses.

Yield Parameters:



563
564
565
566
567
568
569
# File 'lib/roby/executable_plan.rb', line 563

def on_exception(matcher, &handler)
    check_arity(handler, 2)
    exception_handlers.unshift [matcher.to_execution_exception_matcher, handler]
    Roby.disposable do
        exception_handlers.delete_if { |_, h| h == handler }
    end
end

#quarantine_task(task, reason: nil) ⇒ Object

Mark the task as quarantined

Quarantined tasks are essentially tasks that are present in the plan, but cannot be used because they are known to misbehave and themselves can't be killed. The prime example is a task the system tried to stop but for which the stop process failed.

Once set it cannot be unset. The engine will generate a QuarantinedTaskError error as long as there are tasks that depend on the task, to make sure that anything that depend on it either stops using it, or is killed itself.

Parameters:

  • reason (Exception, String, nil) (defaults to: nil)

    if the quarantine was caused by an exception, pass it.there. It will be stored in #quarantine_reason and will be made available in the Quarantine error. Otherwise, pass a message that explains the quarantine



67
68
69
# File 'lib/roby/executable_plan.rb', line 67

def quarantine_task(task, reason: nil)
    task.quarantined!(reason: reason)
end

#quarantined_task_in_use?(task) ⇒ Boolean

Check whether the given quarantined task is in use

It is used to determine whether a QuarantinedTaskError should be generated

Parameters:

  • task (Task)

    a quarantined task

Returns:

  • (Boolean)


170
171
172
173
174
175
176
177
178
179
180
# File 'lib/roby/executable_plan.rb', line 170

def quarantined_task_in_use?(task)
    return true if mission_task?(task) || permanent_task?(task)

    default_useful_task_graphs.each do |g|
        g.each_in_neighbour(task) do |parent_t|
            return true unless parent_t.finished? || parent_t.quarantined?
        end
    end

    false
end

#refresh_relationsObject



86
87
88
89
# File 'lib/roby/executable_plan.rb', line 86

def refresh_relations
    super
    execution_engine.refresh_relations
end

#register_quarantined_task(task) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper to #quaratine_task



74
75
76
77
# File 'lib/roby/executable_plan.rb', line 74

def register_quarantined_task(task)
    log(:quarantined_task, droby_id, task)
    @quarantined_tasks << task
end

#remove_task(object, timestamp = nil) ⇒ Object

Actually remove a task from the plan



572
573
574
575
576
577
578
579
580
581
582
583
# File 'lib/roby/executable_plan.rb', line 572

def remove_task(object, timestamp = nil)
    if object.respond_to?(:running?) && object.running? && object.self_owned?
        raise ArgumentError,
              "attempting to remove #{object}, which is a running task, "\
              "from an executable plan"
    end

    super

    @force_gc.delete(object)
    @quarantined_tasks.delete(object)
end

#removed_edge(parent, child, relations) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hook called after an edge has been removed from this plan

Parameters:

  • parent (Object)

    the child object

  • child (Object)

    the child object

  • relations (Array<Class<Relations::Graph>>)

    the graphs in which an edge has been removed



345
346
347
348
349
350
351
352
353
354
# File 'lib/roby/executable_plan.rb', line 345

def removed_edge(parent, child, relations)
    relations.each do |rel|
        if (name = rel.child_name)
            parent.send("removed_#{name}", child)
            child.send("removed_#{name}_parent", parent)
        end
    end

    log(:removed_edge, parent, child, relations)
end

#removing_edge(parent, child, relations) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hook called before an edge gets removed from this plan

If an exception is raised, the edge will not be removed

Parameters:

  • parent (Object)

    the parent object

  • child (Object)

    the child object

  • relations (Array<Class<Relations::Graph>>)

    the graphs in which an edge is being removed



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/roby/executable_plan.rb', line 315

def removing_edge(parent, child, relations)
    unless parent.read_write? || child.child.read_write?
        raise OwnershipError,
              "cannot remove a relation between two objects we don't own"
    end

    relations.each do |rel|
        if (name = rel.child_name)
            parent.send("removing_#{name}", child)
            child.send("removing_#{name}_parent", parent)
        end
    end

    for trsc in transactions
        next unless trsc.proxying?
        next unless (parent_proxy = trsc[parent, create: false])
        next unless (child_proxy = trsc[child, create: false])

        trsc.removing_plan_relation(parent_proxy, child_proxy, relations)
    end
end

#respawn(task) ⇒ Object

Replace task with a fresh copy of itself and start it.

See #recreate for details about the new task.



595
596
597
598
599
# File 'lib/roby/executable_plan.rb', line 595

def respawn(task)
    new = recreate(task)
    execution_engine.once { new.start!(nil) }
    new
end

#updated_edge_info(parent, child, relation, info) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hook called when the edge information of an existing edge has been updated

Parameters:

  • parent

    the edge parent object

  • child

    the edge child object

  • relation (Class<Relations::Graph>)

    the relation graph ID

  • info (Object)

    the new edge info



300
301
302
303
# File 'lib/roby/executable_plan.rb', line 300

def updated_edge_info(parent, child, relation, info)
    emit_relation_change_hook(parent, child, relation, info, prefix: "updated")
    log(:updated_edge_info, parent, child, relation, info)
end

#updating_edge_info(parent, child, relation, info) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hook called to announce that the edge information of an existing edge will be updated

Parameters:

  • parent

    the edge parent object

  • child

    the edge child object

  • relation (Class<Relations::Graph>)

    the relation graph ID

  • info (Object)

    the new edge info



287
288
289
# File 'lib/roby/executable_plan.rb', line 287

def updating_edge_info(parent, child, relation, info)
    emit_relation_change_hook(parent, child, relation, info, prefix: "updating")
end