Allow read-only Commands to bypass txns in execute()

Since the ovs_idl backend maintains an in-memory copy of the DB,
read-only commands can be executed w/o creating a transaction.
Since it is possible for a function that calls execute() to be
automatically nested into an existing transaction, execute()
wasn't able to access the result since it only happens once the
parent transaction completed. Handling these read-only commands
w/o creating a transaction allows the results to be read and
avoids wasting resources by creating needless transactions.

ReadOnlyCommands can still be used in with transaction(): blocks
with no changes.

Change-Id: I62d6fc2a209535227686a2397b8f7cb169e7d35b
Closes-bug: 1813213
This commit is contained in:
Terry Wilson 2019-01-24 15:37:36 -06:00
parent 0d44123973
commit 692653f49f
4 changed files with 36 additions and 27 deletions

View File

@ -25,12 +25,17 @@ LOG = logging.getLogger(__name__)
class BaseCommand(api.Command):
READ_ONLY = False
def __init__(self, api):
self.api = api
self.result = None
def execute(self, check_error=False, log_errors=True):
try:
if self.READ_ONLY:
self.run_idl(None)
return self.result
with self.api.transaction(check_error, log_errors) as txn:
txn.add(self)
return self.result
@ -60,6 +65,10 @@ class BaseCommand(api.Command):
if k not in ['api', 'result']))
class ReadOnlyCommand(BaseCommand):
READ_ONLY = True
class AddCommand(BaseCommand):
table_name = [] # unhashable, won't be looked up
@ -274,7 +283,7 @@ class DbFindCommand(BaseCommand):
]
class BaseGetRowCommand(BaseCommand):
class BaseGetRowCommand(ReadOnlyCommand):
def __init__(self, api, record):
super(BaseGetRowCommand, self).__init__(api)
self.record = record

View File

@ -41,7 +41,7 @@ class AddManagerCommand(command.AddCommand):
self.result = row.uuid
class GetManagerCommand(BaseCommand):
class GetManagerCommand(command.ReadOnlyCommand):
def __init__(self, api):
super(GetManagerCommand, self).__init__(api)
@ -143,7 +143,7 @@ class DelBridgeCommand(BaseCommand):
br.delete()
class BridgeExistsCommand(BaseCommand):
class BridgeExistsCommand(command.ReadOnlyCommand):
def __init__(self, api, name):
super(BridgeExistsCommand, self).__init__(api)
self.name = name
@ -153,7 +153,7 @@ class BridgeExistsCommand(BaseCommand):
'name', self.name, None))
class ListBridgesCommand(BaseCommand):
class ListBridgesCommand(command.ReadOnlyCommand):
def __init__(self, api):
super(ListBridgesCommand, self).__init__(api)
@ -190,7 +190,7 @@ class DelControllerCommand(BaseCommand):
br.controller = []
class GetControllerCommand(BaseCommand):
class GetControllerCommand(command.ReadOnlyCommand):
def __init__(self, api, bridge):
super(GetControllerCommand, self).__init__(api)
self.bridge = bridge
@ -291,7 +291,7 @@ class DelPortCommand(BaseCommand):
port.delete()
class ListPortsCommand(BaseCommand):
class ListPortsCommand(command.ReadOnlyCommand):
def __init__(self, api, bridge):
super(ListPortsCommand, self).__init__(api)
self.bridge = bridge
@ -301,7 +301,7 @@ class ListPortsCommand(BaseCommand):
self.result = [p.name for p in br.ports if p.name != self.bridge]
class ListIfacesCommand(BaseCommand):
class ListIfacesCommand(command.ReadOnlyCommand):
def __init__(self, api, bridge):
super(ListIfacesCommand, self).__init__(api)
self.bridge = bridge
@ -312,7 +312,7 @@ class ListIfacesCommand(BaseCommand):
for i in p.interfaces]
class PortToBridgeCommand(BaseCommand):
class PortToBridgeCommand(command.ReadOnlyCommand):
def __init__(self, api, name):
super(PortToBridgeCommand, self).__init__(api)
self.name = name
@ -328,7 +328,7 @@ class PortToBridgeCommand(BaseCommand):
self.result = next(br.name for br in bridges if port in br.ports)
class InterfaceToBridgeCommand(BaseCommand):
class InterfaceToBridgeCommand(command.ReadOnlyCommand):
def __init__(self, api, name):
super(InterfaceToBridgeCommand, self).__init__(api)
self.name = name
@ -344,7 +344,7 @@ class InterfaceToBridgeCommand(BaseCommand):
self.result = next(br.name for br in bridges if pname in br.ports)
class GetExternalIdCommand(BaseCommand):
class GetExternalIdCommand(command.ReadOnlyCommand):
def __init__(self, api, table, name, field):
super(GetExternalIdCommand, self).__init__(api)
self.table = table

View File

@ -487,7 +487,7 @@ class LspGetPortSecurityCommand(cmd.BaseCommand):
self.result = lsp.port_security
class LspGetUpCommand(cmd.BaseCommand):
class LspGetUpCommand(cmd.ReadOnlyCommand):
def __init__(self, api, port):
super(LspGetUpCommand, self).__init__(api)
self.port = port
@ -509,7 +509,7 @@ class LspSetEnabledCommand(cmd.BaseCommand):
lsp.enabled = self.is_enabled
class LspGetEnabledCommand(cmd.BaseCommand):
class LspGetEnabledCommand(cmd.ReadOnlyCommand):
def __init__(self, api, port):
super(LspGetEnabledCommand, self).__init__(api)
self.port = port
@ -531,7 +531,7 @@ class LspSetTypeCommand(cmd.BaseCommand):
lsp.type = self.port_type
class LspGetTypeCommand(cmd.BaseCommand):
class LspGetTypeCommand(cmd.ReadOnlyCommand):
def __init__(self, api, port):
super(LspGetTypeCommand, self).__init__(api)
self.port = port
@ -552,7 +552,7 @@ class LspSetOptionsCommand(cmd.BaseCommand):
lsp.options = self.options
class LspGetOptionsCommand(cmd.BaseCommand):
class LspGetOptionsCommand(cmd.ReadOnlyCommand):
def __init__(self, api, port):
super(LspGetOptionsCommand, self).__init__(api)
self.port = port
@ -573,7 +573,7 @@ class LspSetDhcpV4OptionsCommand(cmd.BaseCommand):
lsp.dhcpv4_options = self.dhcpopt_uuid
class LspGetDhcpV4OptionsCommand(cmd.BaseCommand):
class LspGetDhcpV4OptionsCommand(cmd.ReadOnlyCommand):
def __init__(self, api, port):
super(LspGetDhcpV4OptionsCommand, self).__init__(api)
self.port = port
@ -610,7 +610,7 @@ class DhcpOptionsDelCommand(cmd.BaseCommand):
dhcpopt.delete()
class DhcpOptionsListCommand(cmd.BaseCommand):
class DhcpOptionsListCommand(cmd.ReadOnlyCommand):
def run_idl(self, txn):
self.result = [rowview.RowView(r) for
r in self.api.tables['DHCP_Options'].rows.values()]
@ -631,7 +631,7 @@ class DhcpOptionsSetOptionsCommand(cmd.BaseCommand):
dhcpopt.options = self.options
class DhcpOptionsGetOptionsCommand(cmd.BaseCommand):
class DhcpOptionsGetOptionsCommand(cmd.ReadOnlyCommand):
def __init__(self, api, dhcpopt_uuid):
super(DhcpOptionsGetOptionsCommand, self).__init__(api)
self.dhcpopt_uuid = dhcpopt_uuid
@ -686,7 +686,7 @@ class LrDelCommand(cmd.BaseCommand):
raise RuntimeError(msg)
class LrListCommand(cmd.BaseCommand):
class LrListCommand(cmd.ReadOnlyCommand):
def run_idl(self, txn):
self.result = [rowview.RowView(r) for
r in self.api.tables['Logical_Router'].rows.values()]
@ -763,7 +763,7 @@ class LrpDelCommand(PortDelCommand):
if_exists)
class LrpListCommand(cmd.BaseCommand):
class LrpListCommand(cmd.ReadOnlyCommand):
def __init__(self, api, router):
super(LrpListCommand, self).__init__(api)
self.router = router
@ -784,7 +784,7 @@ class LrpSetEnabledCommand(cmd.BaseCommand):
lrp.enabled = self.is_enabled
class LrpGetEnabledCommand(cmd.BaseCommand):
class LrpGetEnabledCommand(cmd.ReadOnlyCommand):
def __init__(self, api, port):
super(LrpGetEnabledCommand, self).__init__(api)
self.port = port
@ -865,7 +865,7 @@ class LrRouteDelCommand(cmd.BaseCommand):
raise RuntimeError(msg)
class LrRouteListCommand(cmd.BaseCommand):
class LrRouteListCommand(cmd.ReadOnlyCommand):
def __init__(self, api, router):
super(LrRouteListCommand, self).__init__(api)
self.router = router
@ -974,7 +974,7 @@ class LrNatDelCommand(cmd.BaseCommand):
match=self.match_ip)
class LrNatListCommand(cmd.BaseCommand):
class LrNatListCommand(cmd.ReadOnlyCommand):
def __init__(self, api, router):
super(LrNatListCommand, self).__init__(api)
self.router = router
@ -1041,7 +1041,7 @@ class LbDelCommand(cmd.BaseCommand):
raise
class LbListCommand(cmd.BaseCommand):
class LbListCommand(cmd.ReadOnlyCommand):
def run_idl(self, txn):
self.result = [rowview.RowView(r)
for r in self.api.tables['Load_Balancer'].rows.values()]
@ -1086,7 +1086,7 @@ class LrLbDelCommand(cmd.BaseCommand):
raise
class LrLbListCommand(cmd.BaseCommand):
class LrLbListCommand(cmd.ReadOnlyCommand):
def __init__(self, api, router):
super(LrLbListCommand, self).__init__(api)
self.router = router
@ -1135,7 +1135,7 @@ class LsLbDelCommand(cmd.BaseCommand):
raise
class LsLbListCommand(cmd.BaseCommand):
class LsLbListCommand(cmd.ReadOnlyCommand):
def __init__(self, api, switch):
super(LsLbListCommand, self).__init__(api)
self.switch = switch
@ -1170,7 +1170,7 @@ class DnsGetCommand(cmd.BaseGetRowCommand):
table = 'DNS'
class DnsListCommand(cmd.BaseCommand):
class DnsListCommand(cmd.ReadOnlyCommand):
def run_idl(self, txn):
table = self.api.tables['DNS']
self.result = [rowview.RowView(r) for r in table.rows.values()]

View File

@ -75,7 +75,7 @@ class ChassisDelCommand(cmd.BaseCommand):
chassis.delete()
class ChassisListCommand(cmd.BaseCommand):
class ChassisListCommand(cmd.ReadOnlyCommand):
def run_idl(self, txn):
self.result = [rowview.RowView(r)
for r in self.api.tables['Chassis'].rows.values()]