Browse Source

merge_new_data: merge aliased nodes

Nodes which are an alias of another node are removed from the storage
after their data got merged in the "base" node.

Special attention is paid to the 'type' field as typically at most one
of the copies has a special node type (i.e. 'gateway').
Helge Jung 9 years ago
parent
commit
ffb3953cf8
1 changed files with 48 additions and 0 deletions
  1. 48 0
      ffstatus/basestorage.py

+ 48 - 0
ffstatus/basestorage.py

@@ -146,12 +146,60 @@ class BaseStorage(object):
                 else:
                     aliased_nodes[alias_id] = [itemid]
 
+        # merge aliased nodes
+        for alias_id in aliased_nodes:
+            if len(aliased_nodes[alias_id]) != 1:
+                logging.warn("Node '%s' is aliased by multiple nodes: %s",
+                             alias_id, aliased_nodes[alias_id])
+                continue
+
+            # target's id is the single entry of the alias list
+            item_id = aliased_nodes[alias_id][0]
+
+            if alias_id == item_id:
+                # the node has itself as alias -> remove the alias entry
+                if alias_id in updated and 'aliases' in updated[alias_id]:
+                    updated[alias_id]['aliases'].remove(alias_id)
+                    logging.debug("Removed self-alias of '%s'.", alias_id)
+                continue
+
+            # look for alias node
+            alias = updated.get(alias_id, current.get(alias_id))
+            if alias is None:
+                # no alias node present already, as we're trying to achieve here
+                continue
+
+            # look for target node
+            item = updated.get(item_id, current.get(item_id))
+            if item is None:
+                logging.warn("Alias node '%s' is missing its target '%s.",
+                             alias_id, item_id)
+                continue
+
+            # merge data
+            item_type = item.get('type', 'node')
+            update = ffstatus.dict_merge(item, alias, overwrite_lists=False)
+            update['node_id'] = item_id  # keep original item's id
+            if item_type != 'node' and update.get('type', 'node') == 'node':
+                # revert overwriting of special node type
+                update['type'] = item_type
+            updated[item_id] = update
+            logging.debug("Merged alias '%s' into '%s'.", alias_id, item_id)
+
+            # mark alias node for deletion
+            updated[alias_id] = None
+
         # sanitize each item's data
         for itemid in updated:
             if itemid.startswith('__'):
                 continue
             item = updated[itemid]
 
+            # delete node if requested
+            if item is None:
+                self.set_node_data(itemid, None)
+                continue
+
             # ensure 'node_id' is set
             if not 'node_id' in item:
                 item['node_id'] = itemid