]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- some good inlinings to the whole cascade_iterator() thing.
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 18 Dec 2010 17:14:23 +0000 (12:14 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 18 Dec 2010 17:14:23 +0000 (12:14 -0500)
cascade_iterator() should probably not yield the "instance" at all
and only deal in states.   30-40K methods taken off the orm2010 test.

lib/sqlalchemy/dialects/sqlite/base.py
lib/sqlalchemy/orm/dependency.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/orm/session.py
lib/sqlalchemy/orm/unitofwork.py
test/perf/orm2010.py

index 47a43bdf115641b4b21eb387849f52b7df5a7c8e..2f293374647275f343458cb1cd5fafe618c9f2ff 100644 (file)
@@ -440,7 +440,7 @@ class SQLiteDialect(default.DefaultDialect):
         qtable = quote(table_name)
         cursor = _pragma_cursor(connection.execute("%stable_info(%s)" % (pragma, qtable)))
         row = cursor.fetchone()
-
+        
         # consume remaining rows, to work around
         # http://www.sqlite.org/cvstrac/tktview?tn=1884
         while cursor.fetchone() is not None:
index 39ea1db35c3c8a4d9ac7fd914718818f4c631e26..35b197f636c98146cefdc6dff6f1133a7b919901 100644 (file)
@@ -152,7 +152,7 @@ class DependencyProcessor(object):
             # detect if there's anything changed or loaded
             # by a preprocessor on this state/attribute.  if not,
             # we should be able to skip it entirely.
-            sum_ = attributes.get_all_pending(state, state.dict, self.key)
+            sum_ = state.manager[self.key].impl.get_all_pending(state, state.dict)
             
             if not sum_:
                 continue
@@ -439,10 +439,10 @@ class OneToManyDP(DependencyProcessor):
                     elif self.hasparent(child) is False:
                         uowcommit.register_object(child, isdelete=True, 
                                             operation="delete", prop=self.prop)
-                        for c, m in self.mapper.cascade_iterator(
+                        for c, m, st_, dct_ in self.mapper.cascade_iterator(
                                                     'delete', child):
                             uowcommit.register_object(
-                                attributes.instance_state(c),
+                                st_,
                                 isdelete=True)
 
             if pks_changed:
@@ -661,10 +661,10 @@ class ManyToOneDP(DependencyProcessor):
                             continue
                         uowcommit.register_object(child, isdelete=True, 
                                         operation="delete", prop=self.prop)
-                        for c, m in self.mapper.cascade_iterator(
+                        for c, m, st_, dct_ in self.mapper.cascade_iterator(
                                                             'delete', child):
                             uowcommit.register_object(
-                                attributes.instance_state(c), isdelete=True)
+                                st_, isdelete=True)
         
     def presort_saves(self, uowcommit, states):
         for state in states:
@@ -681,10 +681,10 @@ class ManyToOneDP(DependencyProcessor):
                             uowcommit.register_object(child, isdelete=True, 
                                         operation="delete", prop=self.prop)
                                             
-                            for c, m in self.mapper.cascade_iterator(
+                            for c, m, st_, dct_ in self.mapper.cascade_iterator(
                                                             'delete', child):
                                 uowcommit.register_object(
-                                    attributes.instance_state(c),
+                                    st_,
                                     isdelete=True)
 
     def process_deletes(self, uowcommit, states):
@@ -939,11 +939,11 @@ class ManyToManyDP(DependencyProcessor):
                     if self.hasparent(child) is False:
                         uowcommit.register_object(child, isdelete=True, 
                                             operation="delete", prop=self.prop)
-                        for c, m in self.mapper.cascade_iterator(
+                        for c, m, st_, dct_ in self.mapper.cascade_iterator(
                                                     'delete', 
                                                     child):
                             uowcommit.register_object(
-                                attributes.instance_state(c), isdelete=True)
+                                st_, isdelete=True)
     
     def process_deletes(self, uowcommit, states):
         secondary_delete = []
index 48c37f80d7731ccef57e0a23fda105719c03459f..8bd8bf3c801bb5daae9bb839251c577bfda34001 100644 (file)
@@ -1382,10 +1382,10 @@ class Mapper(object):
         reference so that they don't fall out of scope immediately.
 
         """
-        visited_instances = util.IdentitySet()
+        visited_states = set()
         prp, mpp = object(), object()
 
-        visitables = [(deque(self._props.values()), prp, state, state.dict)]
+        visitables = deque([(deque(self._props.values()), prp, state, state.dict)])
 
         while visitables:
             iterator, item_type, parent_state, parent_dict = visitables[-1]
@@ -1398,13 +1398,13 @@ class Mapper(object):
                 if type_ not in prop.cascade:
                     continue
                 queue = deque(prop.cascade_iterator(type_, parent_state, 
-                            parent_dict, visited_instances, halt_on))
+                            parent_dict, visited_states, halt_on))
                 if queue:
                     visitables.append((queue,mpp, None, None))
             elif item_type is mpp:
                 instance, instance_mapper, corresponding_state, \
                                 corresponding_dict = iterator.popleft()
-                yield (instance, instance_mapper)
+                yield instance, instance_mapper, corresponding_state, corresponding_dict
                 visitables.append((deque(instance_mapper._props.values()), 
                                         prp, corresponding_state, corresponding_dict))
 
index 239159f3e4759ffe27a5695ec4bc3ba582fb82a6..1b144ea74e8637267c11b2260ac08eb5ed083805 100644 (file)
@@ -820,7 +820,7 @@ class RelationshipProperty(StrategizedProperty):
                 dest_state.get_impl(self.key).set(dest_state,
                         dest_dict, obj, None)
 
-    def cascade_iterator(self, type_, state, dict_, visited_instances, halt_on=None):
+    def cascade_iterator(self, type_, state, dict_, visited_states, halt_on=None):
         if not type_ in self.cascade:
             return
 
@@ -831,7 +831,7 @@ class RelationshipProperty(StrategizedProperty):
             passive = attributes.PASSIVE_OFF
 
         if type_ == 'save-update':
-            instances = attributes.get_all_pending(state, dict_, self.key)
+            instances = state.manager[self.key].impl.get_all_pending(state, dict_)
             
         else:
             instances = state.value_as_iterable(dict_, self.key,
@@ -842,10 +842,12 @@ class RelationshipProperty(StrategizedProperty):
         if instances:
             for c in instances:
                 if c is not None and \
-                    c is not attributes.PASSIVE_NO_RESULT and \
-                    c not in visited_instances:
-                    
+                    c is not attributes.PASSIVE_NO_RESULT:
+
                     instance_state = attributes.instance_state(c)
+                    if instance_state in visited_states:
+                        continue
+                        
                     instance_dict = attributes.instance_dict(c)
                     
                     if halt_on and halt_on(instance_state):
@@ -865,7 +867,7 @@ class RelationshipProperty(StrategizedProperty):
                                                 c.__class__
                                             ))
 
-                    visited_instances.add(c)
+                    visited_states.add(instance_state)
 
                     # cascade using the mapper local to this 
                     # object, so that its individual properties are located
index e2c1308b8927f4ac4fb4f652f758a6c0e3aff671..ba1a38bb9f97ffbbad34a4a694ab06e58ba577df 100644 (file)
@@ -1105,13 +1105,10 @@ class Session(object):
 
     def _save_or_update_state(self, state):
         self._save_or_update_impl(state)
-        self._cascade_save_or_update(state)
 
-    def _cascade_save_or_update(self, state):
-        for state, mapper in _cascade_unknown_state_iterator(
-                                    'save-update', state, 
-                                    halt_on=self._contains_state):
-            self._save_or_update_impl(state)
+        mapper = _state_mapper(state)
+        for o, m, st_, dct_ in mapper.cascade_iterator('save-update', state, halt_on=self._contains_state):
+            self._save_or_update_impl(st_)
 
     def delete(self, instance):
         """Mark an instance as deleted.
@@ -1603,13 +1600,8 @@ def _cascade_state_iterator(cascade, state, **kwargs):
     # yield the state, object, mapper.  yielding the object
     # allows the iterator's results to be held in a list without
     # states being garbage collected
-    for (o, m) in mapper.cascade_iterator(cascade, state, **kwargs):
-        yield attributes.instance_state(o), o, m
-
-def _cascade_unknown_state_iterator(cascade, state, **kwargs):
-    mapper = _state_mapper(state)
-    for (o, m) in mapper.cascade_iterator(cascade, state, **kwargs):
-        yield _state_for_unknown_persistence_instance(o), m
+    for o, m, st_, dct_ in mapper.cascade_iterator(cascade, state, **kwargs):
+        yield st_, o, m
 
 def _state_for_unsaved_instance(instance, create=False):
     try:
index 1e1eda4a3cfcf9e04b751885e43a27a76b035c43..17b73e5f9845e41c6dd47b51edf79fef262ac112 100644 (file)
@@ -28,7 +28,9 @@ class UOWEventHandler(interfaces.AttributeExtension):
     
     def __init__(self, key):
         self.key = key
-
+        
+    # TODO: migrate these to unwrapped events
+    
     def append(self, state, item, initiator):
         # process "save_update" cascade rules for when 
         # an instance is appended to the list of another instance
@@ -36,10 +38,11 @@ class UOWEventHandler(interfaces.AttributeExtension):
         sess = session._state_session(state)
         if sess:
             prop = _state_mapper(state)._props[self.key]
+            item_state = attributes.instance_state(item)
             if prop.cascade.save_update and \
                 (prop.cascade_backrefs or self.key == initiator.key) and \
-                item not in sess:
-                sess.add(item)
+                not sess._contains_state(item_state):
+                sess._save_or_update_state(item_state)
         return item
         
     def remove(self, state, item, initiator):
@@ -47,9 +50,10 @@ class UOWEventHandler(interfaces.AttributeExtension):
         if sess:
             prop = _state_mapper(state)._props[self.key]
             # expunge pending orphans
+            item_state = attributes.instance_state(item)
             if prop.cascade.delete_orphan and \
-                item in sess.new and \
-                prop.mapper._is_orphan(attributes.instance_state(item)):
+                item_state in sess._new and \
+                prop.mapper._is_orphan(item_state):
                     sess.expunge(item)
 
     def set(self, state, newvalue, oldvalue, initiator):
@@ -61,15 +65,19 @@ class UOWEventHandler(interfaces.AttributeExtension):
         sess = session._state_session(state)
         if sess:
             prop = _state_mapper(state)._props[self.key]
-            if newvalue is not None and \
-                prop.cascade.save_update and \
-                (prop.cascade_backrefs or self.key == initiator.key) and \
-                newvalue not in sess:
-                sess.add(newvalue)
-            if prop.cascade.delete_orphan and \
-                oldvalue in sess.new and \
-                prop.mapper._is_orphan(attributes.instance_state(oldvalue)):
-                sess.expunge(oldvalue)
+            if newvalue is not None:
+                newvalue_state = attributes.instance_state(newvalue)
+                if prop.cascade.save_update and \
+                    (prop.cascade_backrefs or self.key == initiator.key) and \
+                    not sess._contains_state(newvalue_state):
+                    sess._save_or_update_state(newvalue_state)
+            
+            if oldvalue is not None and prop.cascade.delete_orphan:
+                oldvalue_state = attributes.instance_state(oldvalue)
+                
+                if oldvalue_state in sess._new and \
+                    prop.mapper._is_orphan(oldvalue_state):
+                    sess.expunge(oldvalue)
         return newvalue
 
 
index 8cdf774aec15ddb9fb5d68b60d4424bf2c055aec..46703b6da6ef5819b058b4686caf7605ee4ac8b9 100644 (file)
@@ -151,6 +151,7 @@ counts_by_methname = dict((key[2], stats.stats[key][0]) for key in stats.stats)
 
 print "SQLA Version: %s" % __version__
 print "Total calls %d" % stats.total_calls
+print "Total cpu seconds: %.2f" % stats.total_tt
 print 'Total execute calls: %d' \
     % counts_by_methname["<method 'execute' of 'sqlite3.Cursor' "
                          "objects>"]