[PATCH phosphor-objmgr 4/7] Add cache access and signal validation wrappers

OpenBMC Patches openbmc-patches at stwcx.xyz
Fri Apr 15 23:00:44 AEST 2016


From: Brad Bishop <bradleyb at us.ibm.com>

Use of the main cache structure will grow so added some wrappers
that automate initialization and cleanup.

Refactored duplicate signal handler bus/interface validation
logic into reusable functions.

Updated discovery and signal handlers to make use of all these
new functions.
---
 phosphor-mapper | 139 +++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 82 insertions(+), 57 deletions(-)

diff --git a/phosphor-mapper b/phosphor-mapper
index 5995ee0..bf0e832 100644
--- a/phosphor-mapper
+++ b/phosphor-mapper
@@ -25,6 +25,7 @@ from obmc.dbuslib.introspection import IntrospectionParser
 import obmc.utils.pathtree
 import obmc.utils.misc
 import obmc.mapper
+import obmc.dbuslib.bindings
 
 
 class MapperNotFoundException(dbus.exceptions.DBusException):
@@ -74,41 +75,22 @@ class ObjectMapper(dbus.service.Object):
         return not bool(self.service)
 
     def interfaces_added_handler(self, path, iprops, **kw):
-        name = self.bus.get_owned_name(self.bus_match, kw['sender'])
-        if self.discovery_pending() or \
-                not self.bus_match(name):
-            return
-
-        matches = [x for x in iprops.iterkeys() if self.intf_match(x)]
-        self.add_interfaces(path, kw['sender'], matches)
+        path = str(path)
+        owner = str(kw['sender'])
+        interfaces = self.get_signal_interfaces(owner, iprops.iterkeys())
+        cache_entry = self.cache.get(path, {})
+        old = self.interfaces_get(cache_entry, owner)
+        new = list(set(interfaces).union(old))
+        self.update_interfaces(path, owner, old, new)
 
     def interfaces_removed_handler(self, path, interfaces, **kw):
-        name = self.bus.get_owned_name(self.bus_match, kw['sender'])
-        if self.discovery_pending() or \
-                not self.bus_match(name):
-            return
-        item = self.cache[path]
-        sender = kw['sender']
-        for x in interfaces:
-            if self.intf_match(x):
-                try:
-                    item[sender].remove(x)
-                except ValueError:
-                    pass
-
-        # remove the owner if there aren't any interfaces left
-        if not item[sender]:
-            del item[sender]
-
-        # update if interfaces remain
-        if item:
-            self.cache[path] = item
-        # mark for removal if no interfaces remain
-        elif self.cache.get_children(path):
-            self.cache.demote(path)
-        # delete the entire path if everything is gone
-        else:
-            del self.cache[path]
+        path = str(path)
+        owner = str(kw['sender'])
+        interfaces = self.get_signal_interfaces(owner, interfaces)
+        cache_entry = self.cache.get(path, {})
+        old = self.interfaces_get(cache_entry, owner)
+        new = list(set(old).difference(interfaces))
+        self.update_interfaces(path, owner, old, new)
 
     def process_new_owner(self, name):
         # unique name
@@ -118,35 +100,34 @@ class ObjectMapper(dbus.service.Object):
                              self.intf_match)])
 
     def process_old_owner(self, name):
-        for x, y in self.cache.dataitems():
-            if name not in y:
-                continue
-            del y[name]
-            if y:
-                self.cache[x] = y
-            elif self.cache.get_children(x):
-                self.cache.demote(x)
-            else:
-                del self.cache[x]
-
-    def bus_handler(self, service, old, new):
-        if self.discovery_pending() or \
-                not self.bus_match(service):
-            return
-
-        if new:
+        for path, item in self.cache.dataitems():
+            old = self.interfaces_get(item, name)
+            # remove all interfaces for this service
+            self.update_interfaces(
+                path, name, old=old, new=[])
+
+    def bus_handler(self, owner, old, new):
+        valid = False
+        if not obmc.dbuslib.bindings.is_unique(owner):
+            valid = self.valid_signal(owner)
+
+        if valid and new:
             self.process_new_owner(new)
-        if old:
+        if valid and old:
             self.process_old_owner(old)
 
-    def add_interfaces(self, path, owner, interfaces):
-        d = self.cache.setdefault(path, {})
-        d = d.setdefault(owner, [])
-        self.cache[path][owner] = list(set(d + interfaces))
+    def update_interfaces(self, path, owner, old, new):
+        cache_entry = self.cache.setdefault(path, {})
+        added = list(set(new).difference(old))
+        removed = list(set(old).difference(new))
+        self.interfaces_append(cache_entry, owner, added)
+        self.interfaces_remove(cache_entry, owner, removed, path)
 
     def add_items(self, owner, bus_items):
-        for x, y in bus_items.iteritems():
-            self.add_interfaces(x, owner, y['interfaces'])
+        for path, items in bus_items.iteritems():
+            # convert dbus types to native.
+            interfaces = [str(i) for i in items.get('interfaces', [])]
+            self.update_interfaces(path, str(owner), old=[], new=interfaces)
 
     def discover(self, owners=None):
         if not owners:
@@ -162,6 +143,50 @@ class ObjectMapper(dbus.service.Object):
             self.service = dbus.service.BusName(
                 obmc.mapper.MAPPER_NAME, self.bus.dbus)
 
+    def valid_signal(self, owner):
+        if obmc.dbuslib.bindings.is_unique(owner):
+            owner = self.bus.get_owned_name(self.bus_match, owner)
+
+        return owner is not None and not self.discovery_pending() and \
+            self.bus_match(owner)
+
+    def get_signal_interfaces(self, owner, interfaces):
+        filtered = []
+        if self.valid_signal(owner):
+            filtered = [str(x) for x in interfaces if self.intf_match(x)]
+
+        return filtered
+
+    @staticmethod
+    def interfaces_get(item, owner, default=[]):
+        return item.get(owner, default)
+
+    @staticmethod
+    def interfaces_append(item, owner, append):
+        interfaces = item.setdefault(owner, [])
+        item[owner] = list(set(append).union(interfaces))
+
+    def interfaces_remove(self, item, owner, remove, path):
+        interfaces = item.get(owner, [])
+        item[owner] = list(set(interfaces).difference(remove))
+
+        if not item[owner]:
+            # remove the owner if there aren't any interfaces left
+            del item[owner]
+
+        if item:
+            # other owners remain
+            return
+
+        if self.cache.get_children(path):
+            # there are still references to this path
+            # from objects further down the tree.
+            # mark it for removal if that changes
+            self.cache.demote(path)
+        else:
+            # delete the entire path if everything is gone
+            del self.cache[path]
+
     @dbus.service.method(obmc.mapper.MAPPER_IFACE, 's', 'a{sas}')
     def GetObject(self, path):
         o = self.cache.get(path)
-- 
2.7.1




More information about the openbmc mailing list