Comment 5 for bug 1824299

Revision history for this message
Mike Bayer (zzzeek) wrote :

ah yes, this is a bug, probably in Neutron's import system though there may be a way to address it in SQLAlchemy by adding a mutex, it's a race. note that the stack trace is generated on a different request id while the SQLAlchemy ORM logging shows it is still in the process of mapping the BGPVPNPortAssociationRoute class itself.

What I need to understand is how is the bgvpn_db.py module being imported? That is, above the logging given above, I assume there's some kind of dynamic module importing that occurs within a service thread and is not simply when the whole application starts up?

I'd like you to try this patch in SQLAlchemy assuming you can reproduce, if you can tell me the specific SQLAlchemy version that's here I can reformat this patch against that version, this is against latest 1.2, the method in question is the "def mapper()" inside of relationships.py:

diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py
index 356b673b66..014004f005 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -45,7 +45,7 @@ from ..sql.util import ClauseAdapter
 from ..sql.util import join_condition
 from ..sql.util import selectables_overlap
 from ..sql.util import visit_binary_product
-
+from .mapper import _CONFIGURE_MUTEX

 def remote(expr):
     """Annotate a portion of a primaryjoin expression
@@ -1724,23 +1724,29 @@ class RelationshipProperty(StrategizedProperty):
         This is a lazy-initializing static attribute.

         """
- if util.callable(self.argument) and not isinstance(
- self.argument, (type, mapperlib.Mapper)
- ):
- argument = self.argument()
- else:
- argument = self.argument

- if isinstance(argument, type):
- mapper_ = mapperlib.class_mapper(argument, configure=False)
- elif isinstance(self.argument, mapperlib.Mapper):
- mapper_ = argument
- else:
- raise sa_exc.ArgumentError(
- "relationship '%s' expects "
- "a class or a mapper argument (received: %s)"
- % (self.key, type(argument))
- )
+ _CONFIGURE_MUTEX.acquire()
+ try:
+ if util.callable(self.argument) and not isinstance(
+ self.argument, (type, mapperlib.Mapper)
+ ):
+ argument = self.argument()
+ else:
+ argument = self.argument
+
+ if isinstance(argument, type):
+ mapper_ = mapperlib.class_mapper(argument, configure=False)
+ elif isinstance(self.argument, mapperlib.Mapper):
+ mapper_ = argument
+ else:
+ raise sa_exc.ArgumentError(
+ "relationship '%s' expects "
+ "a class or a mapper argument (received: %s)"
+ % (self.key, type(argument))
+ )
+ finally:
+ _CONFIGURE_MUTEX.release()
+
         return mapper_

     @util.memoized_property