summaryrefslogtreecommitdiff
path: root/python/ovs/db
diff options
context:
space:
mode:
authorTerry Wilson <twilson@redhat.com>2021-03-09 14:34:16 +0000
committerIlya Maximets <i.maximets@ovn.org>2021-03-15 16:37:20 +0100
commit64b8c1d9ade2a9abc09a6472af5badddd600a3f8 (patch)
treea5210b544ace720aec19c5c355f02497b99577bc /python/ovs/db
parentcdaa7e0fd60d94f95925f1a498f61698675deacc (diff)
downloadopenvswitch-64b8c1d9ade2a9abc09a6472af5badddd600a3f8.tar.gz
python: Send notifications after the transaction ends.
The Python IDL notification mechanism was sending a notification for each processed update in a transaction as it was processed. This causes issues with multi-row changes that contain references to each other. For example, if a Logical_Router_Port is created along with a Gateway_Chassis, and the LRP.gateway_chassis set to that GC, then when the notify() passes the CREATE event for the LRP, the GC will not yet have been processed, so __getattr__ when _uuid_to_row fails to find the GC, will return the default value for LRP.gateway_chassis which is []. This patch has the process_update methods return the notifications that would be produced when a row changes, so they can be queued and sent after all rows have been processed. Fixes: d7d417fcddf9 ("Allow subclasses of Idl to define a notification hook") Signed-off-by: Terry Wilson <twilson@redhat.com> Acked-by: Brian Haley <haleyb.dev@gmail.com> Acked-by: Dumitru Ceara <dceara@redhat.com> Tested-by: Flavio Fernandes <flavio@flaviof.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Diffstat (limited to 'python/ovs/db')
-rw-r--r--python/ovs/db/idl.py39
1 files changed, 24 insertions, 15 deletions
diff --git a/python/ovs/db/idl.py b/python/ovs/db/idl.py
index 5850ac7ab..4226d1cb2 100644
--- a/python/ovs/db/idl.py
+++ b/python/ovs/db/idl.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import collections
import functools
import uuid
@@ -39,6 +40,10 @@ OVSDB_UPDATE2 = 1
CLUSTERED = "clustered"
+Notice = collections.namedtuple('Notice', ('event', 'row', 'updates'))
+Notice.__new__.__defaults__ = (None,) # default updates=None
+
+
class Idl(object):
"""Open vSwitch Database Interface Definition Language (OVSDB IDL).
@@ -614,6 +619,7 @@ class Idl(object):
raise error.Error("<table-updates> is not an object",
table_updates)
+ notices = []
for table_name, table_update in table_updates.items():
table = tables.get(table_name)
if not table:
@@ -639,7 +645,9 @@ class Idl(object):
% (table_name, uuid_string))
if version == OVSDB_UPDATE2:
- if self.__process_update2(table, uuid, row_update):
+ changes = self.__process_update2(table, uuid, row_update)
+ if changes:
+ notices.append(changes)
self.change_seqno += 1
continue
@@ -652,17 +660,20 @@ class Idl(object):
raise error.Error('<row-update> missing "old" and '
'"new" members', row_update)
- if self.__process_update(table, uuid, old, new):
+ changes = self.__process_update(table, uuid, old, new)
+ if changes:
+ notices.append(changes)
self.change_seqno += 1
+ for notice in notices:
+ self.notify(*notice)
def __process_update2(self, table, uuid, row_update):
+ """Returns Notice if a column changed, False otherwise."""
row = table.rows.get(uuid)
- changed = False
if "delete" in row_update:
if row:
del table.rows[uuid]
- self.notify(ROW_DELETE, row)
- changed = True
+ return Notice(ROW_DELETE, row)
else:
# XXX rate-limit
vlog.warn("cannot delete missing row %s from table"
@@ -681,29 +692,27 @@ class Idl(object):
changed = self.__row_update(table, row, row_update)
table.rows[uuid] = row
if changed:
- self.notify(ROW_CREATE, row)
+ return Notice(ROW_CREATE, row)
elif "modify" in row_update:
if not row:
raise error.Error('Modify non-existing row')
old_row = self.__apply_diff(table, row, row_update['modify'])
- self.notify(ROW_UPDATE, row, Row(self, table, uuid, old_row))
- changed = True
+ return Notice(ROW_UPDATE, row, Row(self, table, uuid, old_row))
else:
raise error.Error('<row-update> unknown operation',
row_update)
- return changed
+ return False
def __process_update(self, table, uuid, old, new):
- """Returns True if a column changed, False otherwise."""
+ """Returns Notice if a column changed, False otherwise."""
row = table.rows.get(uuid)
changed = False
if not new:
# Delete row.
if row:
del table.rows[uuid]
- changed = True
- self.notify(ROW_DELETE, row)
+ return Notice(ROW_DELETE, row)
else:
# XXX rate-limit
vlog.warn("cannot delete missing row %s from table %s"
@@ -723,7 +732,7 @@ class Idl(object):
if op == ROW_CREATE:
table.rows[uuid] = row
if changed:
- self.notify(ROW_CREATE, row)
+ return Notice(ROW_CREATE, row)
else:
op = ROW_UPDATE
if not row:
@@ -737,8 +746,8 @@ class Idl(object):
if op == ROW_CREATE:
table.rows[uuid] = row
if changed:
- self.notify(op, row, Row.from_json(self, table, uuid, old))
- return changed
+ return Notice(op, row, Row.from_json(self, table, uuid, old))
+ return False
def __check_server_db(self):
"""Returns True if this is a valid server database, False otherwise."""