diff options
| author | Terry Wilson <twilson@redhat.com> | 2021-03-09 14:34:16 +0000 |
|---|---|---|
| committer | Ilya Maximets <i.maximets@ovn.org> | 2021-03-15 16:37:20 +0100 |
| commit | 64b8c1d9ade2a9abc09a6472af5badddd600a3f8 (patch) | |
| tree | a5210b544ace720aec19c5c355f02497b99577bc /python/ovs/db | |
| parent | cdaa7e0fd60d94f95925f1a498f61698675deacc (diff) | |
| download | openvswitch-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.py | 39 |
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.""" |
