[PATCH phosphor-objmgr] Avoid introspection during discovery

OpenBMC Patches openbmc-patches at stwcx.xyz
Tue May 17 08:20:42 AEST 2016


From: Brad Bishop <bradleyb at fuzziesquirrel.com>

Speed up discovery by calling GetManagedObjects on any ObjectManagers.
Fall back on introspection for parent elements or services that don't
implement one.
---
 phosphor-mapper | 90 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 77 insertions(+), 13 deletions(-)

diff --git a/phosphor-mapper b/phosphor-mapper
index 675ad40..944f6d4 100644
--- a/phosphor-mapper
+++ b/phosphor-mapper
@@ -21,7 +21,7 @@ import dbus.service
 import dbus.exceptions
 import dbus.mainloop.glib
 import gobject
-from obmc.dbuslib.introspection import IntrospectionParser
+import xml.etree.ElementTree as ET
 import obmc.utils.pathtree
 import obmc.utils.misc
 import obmc.mapper
@@ -37,6 +37,71 @@ class MapperNotFoundException(dbus.exceptions.DBusException):
             "path or object not found: %s" % path)
 
 
+def find_dbus_interfaces(conn, service, path, match):
+    class __FindInterfaces(object):
+        def __init__(self):
+            self.results = {}
+
+        @staticmethod
+        def __introspect(service, path):
+            obj = conn.get_object(service, path, introspect=False)
+            iface = dbus.Interface(obj, dbus.INTROSPECTABLE_IFACE)
+            return iface.Introspect()
+
+        @staticmethod
+        def __get_managed_objects(service, om):
+            obj = conn.get_object(service, om, introspect=False)
+            iface = dbus.Interface(
+                obj, dbus.BUS_DAEMON_IFACE + '.ObjectManager')
+            return iface.GetManagedObjects()
+
+        @staticmethod
+        def __to_path(elements):
+            return '/' + '/'.join(elements)
+
+        @staticmethod
+        def __to_path_elements(path):
+            return filter(bool, path.split('/'))
+
+        def __call__(self, service, path):
+            self.results = {}
+            self.__find_interfaces(service, path)
+            return self.results
+
+        @staticmethod
+        def __match(iface):
+            return iface == dbus.BUS_DAEMON_IFACE + '.ObjectManager' \
+                or match(iface)
+
+        def __find_interfaces(self, service, path):
+            path_elements = self.__to_path_elements(path)
+            path = self.__to_path(path_elements)
+            root = ET.fromstring(self.__introspect(service, path))
+
+            ifaces = filter(
+                self.__match,
+                [x.attrib.get('name') for x in root.findall('interface')])
+            self.results[path] = ifaces
+
+            if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in ifaces:
+                objs = self.__get_managed_objects(service, path)
+                for k, v in objs.iteritems():
+                    self.results[k] = v.keys()
+            else:
+                children = filter(
+                    bool,
+                    [x.attrib.get('name') for x in root.findall('node')])
+                children = [
+                    self.__to_path(
+                        path_elements + self.__to_path_elements(x))
+                    for x in children]
+                for child in children:
+                    if child not in self.results:
+                        self.__find_interfaces(service, child)
+
+    return __FindInterfaces()(service, path)
+
+
 class Association(dbus.service.Object):
     def __init__(self, bus, path, endpoints):
         super(Association, self).__init__(bus, path)
@@ -196,10 +261,12 @@ class ObjectMapper(dbus.service.Object):
 
     def process_new_owner(self, owner):
         # unique name
-        return self.discover([IntrospectionParser(owner,
-                             self.bus.dbus,
-                             self.tag_match,
-                             self.intf_match)])
+        try:
+            return self.discover([owner])
+        except dbus.exceptions.DBusException, e:
+            if obmc.dbuslib.enums.DBUS_UNKNOWN_SERVICE \
+                    not in e.get_dbus_name():
+                raise
 
     def process_old_owner(self, owner):
         for path, item in self.cache.dataitems():
@@ -240,7 +307,7 @@ class ObjectMapper(dbus.service.Object):
     def add_items(self, owner, bus_items):
         for path, items in bus_items.iteritems():
             # convert dbus types to native.
-            interfaces = [str(i) for i in items.get('interfaces', [])]
+            interfaces = [str(i) for i in items]
             self.update_interfaces(path, str(owner), old=[], new=interfaces)
 
     def discover(self, owners=[]):
@@ -248,14 +315,11 @@ class ObjectMapper(dbus.service.Object):
             return iface == dbus.BUS_DAEMON_IFACE + '.ObjectManager' or \
                 self.intf_match(iface)
         if not owners:
-            owners = [
-                IntrospectionParser(
-                    x, self.bus.dbus,
-                    self.tag_match,
-                    match)
-                for x in self.bus.get_owner_names(self.bus_match)]
+            owners = self.bus.get_owner_names(self.bus_match)
         for o in owners:
-            self.add_items(o.name, o.introspect())
+            self.add_items(
+                o,
+                find_dbus_interfaces(self.bus.dbus, o, '/', self.intf_match))
 
         if self.discovery_pending():
             # add my object mananger instance
-- 
2.8.2




More information about the openbmc mailing list