The Python IDL's row_update2 "modify" handling always generated a
ROW_UPDATE notification and bumped change_seqno, even when the diff only
touched columns registered without an alert.  This diverged from the C
IDL, whose ovsdb_idl_modify_row_by_diff() reports whether a monitored
(alerted) column actually changed and only then treats the row as
updated.

Make _apply_diff() report whether an alerted column changed, and have
_process_update2()'s "modify" branch notify only in that case, matching
the C behavior.  This is also a prerequisite for faithfully porting the
inconsistency detection that keys off modify_row_by_diff()'s return
value.

There is no single C commit to port here: the alert gating originates in
C commit c547535a7 ("ovsdb-idl: Make it possible to omit or pay less
attention to columns.") applied to the row-update2 diff path added in
db2b57573 ("lib: add monitor2 support in ovsdb-idl.").  This commit
brings the Python IDL in line with that long-standing C behavior.

De-mangle __apply_diff/__process_update2 to single-underscore names as
they are modified here.

Assisted-by: Claude Opus 4.8 <[email protected]>
Signed-off-by: Terry Wilson <[email protected]>
---
 python/ovs/db/idl.py | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/python/ovs/db/idl.py b/python/ovs/db/idl.py
index fe504a63a..61107c189 100644
--- a/python/ovs/db/idl.py
+++ b/python/ovs/db/idl.py
@@ -962,7 +962,7 @@ class Idl(object):
                 self.cooperative_yield()
 
                 if version in (OVSDB_UPDATE2, OVSDB_UPDATE3):
-                    changes = self.__process_update2(table, uuid, row_update)
+                    changes = self._process_update2(table, uuid, row_update)
                     if changes and tables is not self.server_tables:
                         notices.append(changes)
                         self.change_seqno += 1
@@ -984,7 +984,7 @@ class Idl(object):
         for notice in notices:
             self.notify(*notice)
 
-    def __process_update2(self, table, uuid, row_update):
+    def _process_update2(self, table, uuid, row_update):
         """Returns Notice if a column changed, False otherwise."""
         row = table.rows.get(uuid)
         if "delete" in row_update:
@@ -1015,9 +1015,11 @@ class Idl(object):
                 raise error.Error('Modify non-existing row')
 
             del table.rows[uuid]
-            old_row = self.__apply_diff(table, row, row_update['modify'])
+            old_row, changed = self._apply_diff(table, row,
+                                                row_update['modify'])
             table.rows[uuid] = row
-            return Notice(ROW_UPDATE, row, Row(self, table, uuid, old_row))
+            if changed:
+                return Notice(ROW_UPDATE, row, Row(self, table, uuid, old_row))
         else:
             raise error.Error('<row-update> unknown operation',
                               row_update)
@@ -1152,8 +1154,9 @@ class Idl(object):
                     if column.type.n_min != 0 and not column.type.is_map():
                         row_update[column.name] = self.__column_name(column)
 
-    def __apply_diff(self, table, row, row_diff):
+    def _apply_diff(self, table, row, row_diff):
         old_row = {}
+        changed = False
         for column_name, datum_diff_json in row_diff.items():
             column = table.columns.get(column_name)
             if not column:
@@ -1170,12 +1173,18 @@ class Idl(object):
                           % (column_name, table.name, e))
                 continue
 
-            old_row[column_name] = row._data[column_name].copy()
+            # Datum.diff() mutates the datum in place for sets and maps and
+            # returns 'self', so compare the new value against the pre-diff
+            # copy rather than against row._data[column_name] (which diff()
+            # may already have updated).
+            old = row._data[column_name].copy()
+            old_row[column_name] = old
             datum = row._data[column_name].diff(datum_diff)
-            if datum != row._data[column_name]:
-                row._data[column_name] = datum
+            row._data[column_name] = datum
+            if datum != old and column.alert:
+                changed = True
 
-        return old_row
+        return old_row, changed
 
     def __row_update(self, table, row, row_json):
         changed = False
-- 
2.49.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to