diff --git a/lib/confd/client.py b/lib/confd/client.py index dfbc650630b0f52fffc8368664d0c5ba4c9d8c88..71b5104353a4ad24c00453ba61704067acd0df23 100644 --- a/lib/confd/client.py +++ b/lib/confd/client.py @@ -347,6 +347,12 @@ class ConfdClientRequest(objects.ConfdRequest): class ConfdFilterCallback: """Callback that calls another callback, but filters duplicate results. + @ivar consistent: a dictionary indexed by salt; for each salt, if + all responses ware identical, this will be True; this is the + expected state on a healthy cluster; on inconsistent or + partitioned clusters, this might be False, if we see answers + with the same serial but different contents + """ def __init__(self, callback, logger=None): """Constructor for ConfdFilterCallback @@ -364,6 +370,7 @@ class ConfdFilterCallback: self._logger = logger # answers contains a dict of salt -> answer self._answers = {} + self.consistent = {} def _LogFilter(self, salt, new_reply, old_reply): if not self._logger: @@ -388,6 +395,8 @@ class ConfdFilterCallback: # if we have no answer we have received none, before the expiration. if up.salt in self._answers: del self._answers[up.salt] + if up.salt in self.consistent: + del self.consistent[up.salt] def _HandleReply(self, up): """Handle a single confd reply, and decide whether to filter it. @@ -399,6 +408,8 @@ class ConfdFilterCallback: """ filter_upcall = False salt = up.salt + if salt not in self.consistent: + self.consistent[salt] = True if salt not in self._answers: # first answer for a query (don't filter, and record) self._answers[salt] = up.server_reply @@ -413,6 +424,8 @@ class ConfdFilterCallback: # else: different content, pass up a second answer else: # older or same-version answer (duplicate or outdated, filter) + if up.server_reply.answer != self._answers[salt].answer: + self.consistent[salt] = False filter_upcall = True self._LogFilter(salt, up.server_reply, self._answers[salt])