| 747 | } |
| 748 | |
| 749 | Status MutableGraphView::UpdateFanoutsInternal(NodeDef* from_node, |
| 750 | NodeDef* to_node) { |
| 751 | VLOG(2) << absl::Substitute("Update fanouts from '$0' to '$1'.", |
| 752 | from_node->name(), to_node->name()); |
| 753 | if (from_node == to_node) { |
| 754 | return Status::OK(); |
| 755 | } |
| 756 | |
| 757 | // Update internal state with the new output_port->input_port edge. |
| 758 | const auto add_edge = [this](const OutputPort& output_port, |
| 759 | const InputPort& input_port) { |
| 760 | fanouts()[output_port].insert(input_port); |
| 761 | }; |
| 762 | |
| 763 | // Remove invalidated edge from the internal state. |
| 764 | const auto remove_edge = [this](const OutputPort& output_port, |
| 765 | const InputPort& input_port) { |
| 766 | fanouts()[output_port].erase(input_port); |
| 767 | }; |
| 768 | |
| 769 | // For the control fanouts we do not know the input index in a NodeDef, |
| 770 | // so we have to traverse all control inputs. |
| 771 | |
| 772 | auto control_fanouts = |
| 773 | GetFanout(GraphView::OutputPort(from_node, Graph::kControlSlot)); |
| 774 | |
| 775 | bool to_node_is_switch = IsSwitch(*to_node); |
| 776 | for (const InputPort& control_port : control_fanouts) { |
| 777 | // Node can't be control dependency of itself. |
| 778 | if (control_port.node == to_node) continue; |
| 779 | |
| 780 | // Can't add Switch node as a control dependency. |
| 781 | if (to_node_is_switch) { |
| 782 | // Trying to add a Switch as a control dependency, which if allowed will |
| 783 | // make the graph invalid. |
| 784 | return UpdateFanoutsError(from_node->name(), to_node->name())( |
| 785 | absl::Substitute("can't update fanouts to node '$0' as it will " |
| 786 | "become a Switch control dependency", |
| 787 | to_node->name())); |
| 788 | } |
| 789 | |
| 790 | NodeDef* node = control_port.node; |
| 791 | RemoveControllingFaninInternal(node, from_node); |
| 792 | AddFaninInternal(node, {to_node, Graph::kControlSlot}); |
| 793 | } |
| 794 | |
| 795 | // First we update regular fanouts. For the regular fanouts |
| 796 | // `input_port:port_id` is the input index in NodeDef. |
| 797 | |
| 798 | auto regular_edges = |
| 799 | GetFanoutEdges(*from_node, /*include_controlled_edges=*/false); |
| 800 | |
| 801 | // Maximum index of the `from_node` output tensor that is still used as an |
| 802 | // input to some other node. |
| 803 | int keep_max_regular_output_port = -1; |
| 804 | |
| 805 | for (const Edge& edge : regular_edges) { |
| 806 | const OutputPort output_port = edge.src; |
nothing calls this directly
no test coverage detected