Commit 54ad225c authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

Mojo: Optimize Node::DestroyAllPortsWithPeer

Node::DestroyAllPortsWithPeer is called any time a connection is lost to
a remote Node, allowing the local process to recursively back-propagate
awareness of broken port cycles (and thus disconnected Mojo primitives).

The current implementation of DestroyAllPortsWithPeer turns out to be
O(n^2) *gasp* and the frequency with which this can be called has gone
overlooked for some time. Eep.

This CL has Node maintain a reverse mapping from peer NodeNode+PortName
to the set of all local ports which reference that NodeName+PortName
combo as their peer. This allows for a much more efficient
implementation of DestroyAllPortsWithPeer, particularly in the recursive
branches which typically only affect at most a single local port.

Bug: 922650
Change-Id: Ic0baf822f8735cce5f59a7820a729b748a6875ec
Reviewed-on: https://chromium-review.googlesource.com/c/1433134
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: default avatarErik Chen <erikchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#625841}
parent 04ca4d8a
This diff is collapsed.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <unordered_map> #include <unordered_map>
#include "base/component_export.h" #include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
...@@ -227,18 +228,59 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node { ...@@ -227,18 +228,59 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
void DestroyAllPortsWithPeer(const NodeName& node_name, void DestroyAllPortsWithPeer(const NodeName& node_name,
const PortName& port_name); const PortName& port_name);
// Changes the peer node and port name referenced by |port|. Note that both
// |ports_lock_| MUST be held through the extent of this method.
// |local_port|'s lock must be held if and only if a reference to |local_port|
// exist in |ports_|.
void UpdatePortPeerAddress(const PortName& local_port_name,
Port* local_port,
const NodeName& new_peer_node,
const PortName& new_peer_port);
// Removes an entry from |peer_port_map_| corresponding to |local_port|'s peer
// address, if valid.
void RemoveFromPeerPortMap(const PortName& local_port_name, Port* local_port);
// Swaps the peer information for two local ports. Used during port merges.
// Note that |ports_lock_| must be held along with each of the two port's own
// locks, through the extent of this method.
void SwapPortPeers(const PortName& port0_name,
Port* port0,
const PortName& port1_name,
Port* port1);
const NodeName name_; const NodeName name_;
const DelegateHolder delegate_; const DelegateHolder delegate_;
// Guards |ports_|. This must never be acquired while an individual port's // Just to clarify readability of the types below.
// lock is held on the same thread. Conversely, individual port locks may be using LocalPortName = PortName;
// acquired while this one is held. using PeerPortName = PortName;
// Guards access to |ports_| and |peer_port_maps_| below.
//
// This must never be acquired while an individual port's lock is held on the
// same thread. Conversely, individual port locks may be acquired while this
// one is held.
// //
// Because UserMessage events may execute arbitrary user code during // Because UserMessage events may execute arbitrary user code during
// destruction, it is also important to ensure that such events are never // destruction, it is also important to ensure that such events are never
// destroyed while this (or any individual Port) lock is held. // destroyed while this (or any individual Port) lock is held.
base::Lock ports_lock_; base::Lock ports_lock_;
std::unordered_map<PortName, scoped_refptr<Port>> ports_; std::unordered_map<LocalPortName, scoped_refptr<Port>> ports_;
// Maps a peer port name to a list of PortRefs for all local ports which have
// the port name key designated as their peer port. The set of local ports
// which have the same peer port is expected to always be relatively small and
// usually 1. Hence we just use a flat_map of local PortRefs keyed on each
// local port's name.
using PeerPortMap =
std::unordered_map<PeerPortName, base::flat_map<LocalPortName, PortRef>>;
// A reverse mapping which can be used to find all local ports that reference
// a given peer node or a local port that references a specific given peer
// port on a peer node. The key to this map is the corresponding peer node
// name.
std::unordered_map<NodeName, PeerPortMap> peer_port_maps_;
DISALLOW_COPY_AND_ASSIGN(Node); DISALLOW_COPY_AND_ASSIGN(Node);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment