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_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 DRoby::EventLogging

#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

#initialize(event_logger: DRoby::NullEventLogger.new) ⇒ ExecutablePlan

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(event_logger: DRoby::NullEventLogger.new)
    super(graph_observer: self, event_logger: event_logger)

    @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



268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/roby/executable_plan.rb', line 268

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



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
252
253
254
255
256
# File 'lib/roby/executable_plan.rb', line 223

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



609
610
611
612
613
# File 'lib/roby/executable_plan.rb', line 609

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



160
161
162
163
164
165
166
167
# File 'lib/roby/executable_plan.rb', line 160

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



153
154
155
# File 'lib/roby/executable_plan.rb', line 153

def check_structure
    super.merge(check_quarantined_tasks_in_use)
end

#clearObject

Clear the plan



591
592
593
594
595
# File 'lib/roby/executable_plan.rb', line 591

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



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/roby/executable_plan.rb', line 102

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:



553
554
555
# File 'lib/roby/executable_plan.rb', line 553

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



364
365
366
367
368
369
# File 'lib/roby/executable_plan.rb', line 364

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



376
377
378
379
380
381
382
383
384
385
386
# File 'lib/roby/executable_plan.rb', line 376

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



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/roby/executable_plan.rb', line 392

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

#event_logger=(logger) ⇒ Object



91
92
93
94
# File 'lib/roby/executable_plan.rb', line 91

def event_logger=(logger)
    super
    log :register_executable_plan, droby_id
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



191
192
193
# File 'lib/roby/executable_plan.rb', line 191

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



206
207
208
209
# File 'lib/roby/executable_plan.rb', line 206

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



198
199
200
201
# File 'lib/roby/executable_plan.rb', line 198

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.



535
536
537
538
539
540
541
542
543
# File 'lib/roby/executable_plan.rb', line 535

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.



512
513
514
515
516
517
518
519
520
521
522
# File 'lib/roby/executable_plan.rb', line 512

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



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/roby/executable_plan.rb', line 128

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



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
452
453
454
455
456
# File 'lib/roby/executable_plan.rb', line 418

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



474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/roby/executable_plan.rb', line 474

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



461
462
463
464
465
466
467
468
469
# File 'lib/roby/executable_plan.rb', line 461

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:



568
569
570
571
572
573
574
# File 'lib/roby/executable_plan.rb', line 568

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)


175
176
177
178
179
180
181
182
183
184
185
# File 'lib/roby/executable_plan.rb', line 175

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



577
578
579
580
581
582
583
584
585
586
587
588
# File 'lib/roby/executable_plan.rb', line 577

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



350
351
352
353
354
355
356
357
358
359
# File 'lib/roby/executable_plan.rb', line 350

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



320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/roby/executable_plan.rb', line 320

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.



600
601
602
603
604
# File 'lib/roby/executable_plan.rb', line 600

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



305
306
307
308
# File 'lib/roby/executable_plan.rb', line 305

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



292
293
294
# File 'lib/roby/executable_plan.rb', line 292

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