]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- reworked the internals of mapper.cascade_iterator() to
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 1 Oct 2010 18:23:01 +0000 (14:23 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 1 Oct 2010 18:23:01 +0000 (14:23 -0400)
cut down method calls by about 9% in some circumstances.
[ticket:1932]

CHANGES
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/properties.py
test/aaa_profiling/test_zoomark_orm.py

diff --git a/CHANGES b/CHANGES
index 150cfbfa4f66a06ff28df49aa29452b06ddcce91..c6de24280a28b9398675008c2aba01a4bf838389 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -107,6 +107,10 @@ CHANGES
   - scoped_session emits a warning when configure() is 
     called if a Session is already present (checks only the
     current thread) [ticket:1924]
+
+  - reworked the internals of mapper.cascade_iterator() to
+    cut down method calls by about 9% in some circumstances.
+    [ticket:1932]
     
 - sql
    - Table.tometadata() now copies Index objects associated
index 0a65c8a44f32a300bc86d0cd31ab151f6c7705dd..fa27859ecb22f546c1b32e0db839c5fac27b3220 100644 (file)
@@ -76,7 +76,7 @@ class MapperExtension(object):
     mapper activity will not be performed.
     
     """
-
+    
     def instrument_class(self, mapper, class_):
         """Receive a class when the mapper is first constructed, and has
         applied instrumentation to the mapped class.
@@ -418,6 +418,13 @@ class MapperProperty(object):
     attribute access, loading behavior, and dependency calculations.
     """
 
+    cascade = ()
+    """The set of 'cascade' attribute names.
+    
+    This collection is checked before the 'cascade_iterator' method is called.
+    
+    """
+
     def setup(self, context, entity, path, adapter, **kwargs):
         """Called by Query for the purposes of constructing a SQL statement.
 
@@ -469,6 +476,11 @@ class MapperProperty(object):
                             halt_on=None):
         """Iterate through instances related to the given instance for
         a particular 'cascade', starting with this MapperProperty.
+        
+        Return an iterator3-tuples (instance, mapper, state).
+        
+        Note that the 'cascade' collection on this MapperProperty is
+        checked first for the given type before cascade_iterator is called.
 
         See PropertyLoader for the related instance implementation.
         """
index 49f5d2190f641cedd3772079975808b3b3367d5e..d27b9960183ee7c66bd207489d2dc52b841869e0 100644 (file)
@@ -1401,25 +1401,30 @@ class Mapper(object):
 
         """
         visited_instances = util.IdentitySet()
-        visitables = [(self._props.itervalues(), 'property', state)]
+        prp, mpp = object(), object()
+
+        visitables = [(deque(self._props.values()), prp, state)]
 
         while visitables:
             iterator, item_type, parent_state = visitables[-1]
-            try:
-                if item_type == 'property':
-                    prop = iterator.next()
-                    visitables.append(
-                                (prop.cascade_iterator(type_, parent_state, 
-                                visited_instances, halt_on), 'mapper', None)
-                                )
-                elif item_type == 'mapper':
-                    instance, instance_mapper, corresponding_state  = \
-                                    iterator.next()
-                    yield (instance, instance_mapper)
-                    visitables.append((instance_mapper._props.itervalues(), 
-                                            'property', corresponding_state))
-            except StopIteration:
+            if not iterator:
                 visitables.pop()
+                continue
+                
+            if item_type is prp:
+                prop = iterator.popleft()
+                if type_ not in prop.cascade:
+                    continue
+                queue = deque(prop.cascade_iterator(type_, parent_state, 
+                            visited_instances, halt_on))
+                if queue:
+                    visitables.append((queue,mpp, None))
+            elif item_type is mpp:
+                instance, instance_mapper, corresponding_state  = \
+                                iterator.popleft()
+                yield (instance, instance_mapper)
+                visitables.append((deque(instance_mapper._props.values()), 
+                                        prp, corresponding_state))
 
     @_memoized_compiled_property
     def _compiled_cache(self):
index a5e6930b28921245e6a3ffa4aa54183333852d8f..4efd2acc907bd81c8d38b41a4af8a9e5f44a1e8a 100644 (file)
@@ -868,7 +868,8 @@ class RelationshipProperty(StrategizedProperty):
                     # cascade using the mapper local to this 
                     # object, so that its individual properties are located
                     instance_mapper = instance_state.manager.mapper
-                    yield (c, instance_mapper, instance_state)
+                    yield c, instance_mapper, instance_state
+            
 
     def _add_reverse_property(self, key):
         other = self.mapper.get_property(key, _compile_mappers=False)
index 3e30efa245931f185684d876f4521ff405476405..623ec67ba1780022ede2845a43aca9a44b0b8836 100644 (file)
@@ -335,11 +335,11 @@ class ZooMarkTest(TestBase):
     def test_profile_1_create_tables(self):
         self.test_baseline_1_create_tables()
 
-    @profiling.function_call_count(9225)
+    @profiling.function_call_count(8469)
     def test_profile_1a_populate(self):
         self.test_baseline_1a_populate()
 
-    @profiling.function_call_count(640)
+    @profiling.function_call_count(591)
     def test_profile_2_insert(self):
         self.test_baseline_2_insert()