Index: pacemaker/lib/common/digest.c
===================================================================
--- pacemaker.orig/lib/common/digest.c
+++ pacemaker/lib/common/digest.c
@@ -95,6 +95,7 @@ calculate_xml_digest_v1(xmlNode * input,
  *
  * \return Newly allocated string containing digest
  */
+#if 0
 static char *
 calculate_xml_digest_v2(xmlNode * source, gboolean do_filter)
 {
@@ -144,6 +145,147 @@ calculate_xml_digest_v2(xmlNode * source
     crm_trace("End digest");
     return digest;
 }
+#endif
+
+typedef struct {
+    int found;
+    const char *string;
+} filter_t;
+
+static filter_t filter[] = {
+    { 0, XML_ATTR_ORIGIN },
+    { 0, XML_CIB_ATTR_WRITTEN },
+    { 0, XML_ATTR_UPDATE_ORIG },
+    { 0, XML_ATTR_UPDATE_CLIENT },
+    { 0, XML_ATTR_UPDATE_USER },
+};
+
+static inline const char *
+crm_attr_value(xmlAttr * attr)
+{
+    if (attr == NULL || attr->children == NULL) {
+        return NULL;
+    }
+    return (const char *)attr->children->content;
+}
+
+static inline xmlAttr *
+crm_first_attr(xmlNode * xml)
+{
+    if (xml == NULL) {
+        return NULL;
+    }
+    return xml->properties;
+}
+
+static void
+filter_xml(xmlNode *data, filter_t *filter, int filter_len, gboolean recursive) 
+{
+    int lpc = 0;
+    xmlNode *child = NULL;
+    
+    for(lpc = 0; lpc < filter_len; lpc++) {
+	xml_remove_prop(data, filter[lpc].string);
+    }
+
+    if(recursive == FALSE || filter_len == 0) {
+	return;
+    }
+    
+    for(child = __xml_first_child(data); child != NULL; child = __xml_next(child)) {
+	filter_xml(child, filter, filter_len, recursive);
+    }
+}
+
+static char *
+calculate_xml_digest_v2(xmlNode *source, gboolean do_filter)
+{
+    char *digest = NULL;
+
+    int buffer_len = 0;
+    int filter_size = DIMOF(filter);
+
+    xmlDoc *doc = NULL;
+    xmlNode *copy = NULL;
+    xmlNode *input = source;
+    xmlBuffer *xml_buffer = NULL;
+    static struct qb_log_callsite *digest_cs = NULL;
+
+    crm_trace("Begin digest");
+    if(do_filter && BEST_EFFORT_STATUS) {
+	/* Exclude the status calculation from the digest
+	 *
+	 * This doesn't mean it wont be sync'd, we just wont be paranoid
+	 * about it being an _exact_ copy
+	 *
+	 * We don't need it to be exact, since we throw it away and regenerate
+	 * from our peers whenever a new DC is elected anyway
+	 *
+	 * Importantly, this reduces the amount of XML to copy+export as 
+	 * well as the amount of data for MD5 needs to operate on
+	 */
+	xmlNode *child = NULL;
+        xmlAttrPtr pIter = NULL;
+	copy = create_xml_node(NULL, XML_TAG_CIB);
+        for(pIter = crm_first_attr(input); pIter != NULL; pIter = pIter->next) {
+            const char *p_name = (const char *)pIter->name;
+            const char *p_value = crm_attr_value(pIter);
+
+            xmlSetProp(copy, (const xmlChar*)p_name, (const xmlChar*)p_value);
+        }
+
+	xml_remove_prop(copy, XML_ATTR_ORIGIN);
+	xml_remove_prop(copy, XML_CIB_ATTR_WRITTEN);
+
+	/* We just did all the filtering */
+	
+	for(child = __xml_first_child(input); child != NULL; child = __xml_next(child)) {
+	    if(safe_str_neq(crm_element_name(child), XML_CIB_TAG_STATUS)) {
+		add_node_copy(copy, child);
+	    }
+	}
+	
+    } else if(do_filter) {
+	copy = copy_xml(input);
+	filter_xml(copy, filter, filter_size, TRUE);
+	input = copy;
+    }
+
+    crm_trace("Dumping");
+    doc = getDocPtr(input);
+    xml_buffer = xmlBufferCreate();
+
+    CRM_ASSERT(xml_buffer != NULL);
+    CRM_CHECK(doc != NULL, return NULL); /* doc will only be NULL if an_xml_node is */
+    
+    buffer_len = xmlNodeDump(xml_buffer, doc, input, 0, FALSE);
+    CRM_CHECK(xml_buffer->content != NULL && buffer_len > 0, goto done);
+
+    digest = crm_md5sum((char *)xml_buffer->content);
+
+        if(digest_cs == NULL) {
+            digest_cs = qb_log_callsite_get(
+                __func__, __FILE__, "cib-digest", LOG_TRACE, __LINE__,
+                crm_trace_nonlog);
+        }
+        if (digest_cs && digest_cs->targets) {
+            char *trace_file = crm_concat("/tmp/cib-digest", digest, '-');
+            crm_trace("Saving %s.%s.%s to %s",
+                      crm_element_value(input, XML_ATTR_GENERATION_ADMIN),
+                      crm_element_value(input, XML_ATTR_GENERATION),
+                      crm_element_value(input, XML_ATTR_NUMUPDATES),
+                      trace_file);
+            save_xml_to_file(source, "digest input", trace_file);
+            free(trace_file);
+        }
+
+  done:
+    xmlBufferFree(xml_buffer);
+    free_xml(copy);
+
+    crm_trace("End digest");
+    return digest;
+}
 
 /*!
  * \brief Calculate and return digest of XML tree, suitable for storing on disk
