Add a semaphore to some ML2 operations

This patch adds a semaphore for serializing the delete port API
calls and update_port_status calls to avoid simultaneous
attempts to acquire SQL update locks on the port table from
the same thread pool.

This semaphore has been introduced to avoid undesired eventlet
yields which trigger 'lock wait timeout' errors in the DB backend;
it should have a negligible impact on the overall performance.

Change-Id: I0ec947086e533945942ae93402943dec69b218ef
Partial-Bug: 1283522
This commit is contained in:
Salvatore Orlando 2014-03-13 15:06:12 -07:00 committed by Kevin Benton
parent 3ccb3be933
commit 1dab002ff5

View File

@ -12,6 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import contextlib
from oslo.config import cfg from oslo.config import cfg
from sqlalchemy import exc as sql_exc from sqlalchemy import exc as sql_exc
@ -41,6 +42,7 @@ from neutron.openstack.common import db as os_db
from neutron.openstack.common import excutils from neutron.openstack.common import excutils
from neutron.openstack.common import importutils from neutron.openstack.common import importutils
from neutron.openstack.common import jsonutils from neutron.openstack.common import jsonutils
from neutron.openstack.common import lockutils
from neutron.openstack.common import log from neutron.openstack.common import log
from neutron.openstack.common import rpc as c_rpc from neutron.openstack.common import rpc as c_rpc
from neutron.plugins.common import constants as service_constants from neutron.plugins.common import constants as service_constants
@ -699,7 +701,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
l3plugin.prevent_l3_port_deletion(context, id) l3plugin.prevent_l3_port_deletion(context, id)
session = context.session session = context.session
with session.begin(subtransactions=True): # REVISIT: Serialize this operation with a semaphore to prevent
# undesired eventlet yields leading to 'lock wait timeout' errors
with contextlib.nested(lockutils.lock('db-access'),
session.begin(subtransactions=True)):
try: try:
port_db = (session.query(models_v2.Port). port_db = (session.query(models_v2.Port).
enable_eagerloads(False). enable_eagerloads(False).
@ -735,7 +740,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
def update_port_status(self, context, port_id, status): def update_port_status(self, context, port_id, status):
updated = False updated = False
session = context.session session = context.session
with session.begin(subtransactions=True): # REVISIT: Serialize this operation with a semaphore to prevent
# undesired eventlet yields leading to 'lock wait timeout' errors
with contextlib.nested(lockutils.lock('db-access'),
session.begin(subtransactions=True)):
port = db.get_port(session, port_id) port = db.get_port(session, port_id)
if not port: if not port:
LOG.warning(_("Port %(port)s updated up by agent not found"), LOG.warning(_("Port %(port)s updated up by agent not found"),