]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- some inlining, speed up identity map
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 19 May 2014 20:57:14 +0000 (16:57 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 19 May 2014 20:57:14 +0000 (16:57 -0400)
lib/sqlalchemy/orm/identity.py
lib/sqlalchemy/orm/loading.py
lib/sqlalchemy/orm/state.py

index a91085d286f0f9518bff48e305c7a558643effc2..f9cd99289252d196b1e25a90e01c7fc4e9d0ecbb 100644 (file)
@@ -8,8 +8,9 @@ import weakref
 from . import attributes
 from .. import util
 
-class IdentityMap(dict):
+class IdentityMap(object):
     def __init__(self):
+        self._dict = {}
         self._modified = set()
         self._wr = weakref.ref(self)
 
@@ -19,6 +20,11 @@ class IdentityMap(dict):
     def add(self, state):
         raise NotImplementedError()
 
+    def _add_unpresent(self, state, key):
+        """optional inlined form of add() which can assume item isn't present
+        in the map"""
+        self.add(state)
+
     def update(self, dict):
         raise NotImplementedError("IdentityMap uses add() to insert data")
 
@@ -68,11 +74,9 @@ class IdentityMap(dict):
 
 
 class WeakInstanceDict(IdentityMap):
-    def __init__(self):
-        IdentityMap.__init__(self)
 
     def __getitem__(self, key):
-        state = dict.__getitem__(self, key)
+        state = self._dict[key]
         o = state.obj()
         if o is None:
             raise KeyError(key)
@@ -80,8 +84,8 @@ class WeakInstanceDict(IdentityMap):
 
     def __contains__(self, key):
         try:
-            if dict.__contains__(self, key):
-                state = dict.__getitem__(self, key)
+            if key in self._dict:
+                state = self._dict[key]
                 o = state.obj()
             else:
                 return False
@@ -91,25 +95,25 @@ class WeakInstanceDict(IdentityMap):
             return o is not None
 
     def contains_state(self, state):
-        return dict.get(self, state.key) is state
+        return state.key in self._dict and self._dict[state.key] is state
 
     def replace(self, state):
-        if dict.__contains__(self, state.key):
-            existing = dict.__getitem__(self, state.key)
+        if state.key in self._dict:
+            existing = self._dict[state.key]
             if existing is not state:
                 self._manage_removed_state(existing)
             else:
                 return
 
-        dict.__setitem__(self, state.key, state)
+        self._dict[state.key] = state
         self._manage_incoming_state(state)
 
     def add(self, state):
         key = state.key
         # inline of self.__contains__
-        if dict.__contains__(self, key):
+        if key in self._dict:
             try:
-                existing_state = dict.__getitem__(self, key)
+                existing_state = self._dict[key]
                 if existing_state is not state:
                     o = existing_state.obj()
                     if o is not None:
@@ -121,13 +125,18 @@ class WeakInstanceDict(IdentityMap):
                     return
             except KeyError:
                 pass
-        dict.__setitem__(self, key, state)
+        self._dict[key] = state
         self._manage_incoming_state(state)
 
+    def _add_unpresent(self, state, key):
+        # inlined form of add() called by loading.py
+        self._dict[key] = state
+        state._instance_dict = self._wr
+
     def get(self, key, default=None):
-        state = dict.get(self, key, default)
-        if state is default:
+        if key not in self._dict:
             return default
+        state = self._dict[key]
         o = state.obj()
         if o is None:
             return default
@@ -170,15 +179,16 @@ class WeakInstanceDict(IdentityMap):
 
     def all_states(self):
         if util.py2k:
-            return dict.values(self)
+            return self._dict.values()
         else:
-            return list(dict.values(self))
+            return list(self._dict.values())
 
     def discard(self, state):
-        st = dict.get(self, state.key, None)
-        if st is state:
-            dict.pop(self, state.key, None)
-            self._manage_removed_state(state)
+        if state.key in self._dict:
+            st = self._dict[state.key]
+            if st is state:
+                self._dict.pop(state.key, None)
+                self._manage_removed_state(state)
 
     def prune(self):
         return 0
@@ -194,34 +204,38 @@ class StrongInstanceDict(IdentityMap):
             attributes.instance_state(self[state.key]) is state)
 
     def replace(self, state):
-        if dict.__contains__(self, state.key):
-            existing = dict.__getitem__(self, state.key)
+        if state.key in self._dict:
+            existing = self._dict[state.key]
             existing = attributes.instance_state(existing)
             if existing is not state:
                 self._manage_removed_state(existing)
             else:
                 return
 
-        dict.__setitem__(self, state.key, state.obj())
+        self._dict[state.key] = state.obj()
         self._manage_incoming_state(state)
 
     def add(self, state):
         if state.key in self:
-            if attributes.instance_state(dict.__getitem__(self,
-                    state.key)) is not state:
+            if attributes.instance_state(self._dict[state.key]) is not state:
                 raise AssertionError('A conflicting state is already '
                         'present in the identity map for key %r'
                         % (state.key, ))
         else:
-            dict.__setitem__(self, state.key, state.obj())
+            self._dict[state.key] = state.obj()
             self._manage_incoming_state(state)
 
+    def _add_unpresent(self, state, key):
+        # inlined form of add() called by loading.py
+        self._dict[key] = state.obj()
+        state._instance_dict = self._wr
+
     def discard(self, state):
-        obj = dict.get(self, state.key, None)
-        if obj is not None:
+        if state.key in self._dict:
+            obj = self._dict[state.key]
             st = attributes.instance_state(obj)
             if st is state:
-                dict.pop(self, state.key, None)
+                self._dict.pop(state.key, None)
                 self._manage_removed_state(state)
 
     def prune(self):
@@ -234,7 +248,7 @@ class StrongInstanceDict(IdentityMap):
         keepers = weakref.WeakValueDictionary()
         keepers.update(self)
 
-        dict.clear(self)
-        dict.update(self, keepers)
+        self._dict.clear()
+        self._dict.update(keepers)
         self.modified = bool(dirty)
         return ref_count - len(self)
index b79ea429c604668d5f387f62723b5a27e7cc690f..8fcace9be1226a77aba20c93222cd3291ee05a40 100644 (file)
@@ -84,7 +84,7 @@ def instances(query, cursor, context):
             context.progress.pop(context.refresh_state)
 
         statelib.InstanceState._commit_all_states(
-            list(context.progress.items()),
+            context.progress.items(),
             session.identity_map
         )
 
@@ -319,6 +319,12 @@ def instance_processor(mapper, context, path, adapter,
     populate_existing = context.populate_existing or mapper.always_refresh
     invoke_all_eagers = context.invoke_all_eagers
 
+    load_evt = mapper.class_manager.dispatch.load or None
+    refresh_evt = mapper.class_manager.dispatch.refresh or None
+
+    instance_state = attributes.instance_state
+    instance_dict = attributes.instance_dict
+
     if mapper.allow_partial_pks:
         is_not_primary_key = _none_set.issuperset
     else:
@@ -363,8 +369,8 @@ def instance_processor(mapper, context, path, adapter,
         instance = session_identity_map.get(identitykey)
 
         if instance is not None:
-            state = attributes.instance_state(instance)
-            dict_ = attributes.instance_dict(instance)
+            state = instance_state(instance)
+            dict_ = instance_dict(instance)
 
             isnew = state.runid != context.runid
             currentload = not isnew
@@ -394,7 +400,7 @@ def instance_processor(mapper, context, path, adapter,
             # when eager_defaults is True.
             state = refresh_state
             instance = state.obj()
-            dict_ = attributes.instance_dict(instance)
+            dict_ = instance_dict(instance)
             isnew = state.runid != context.runid
             currentload = True
             loaded_instance = False
@@ -424,13 +430,13 @@ def instance_processor(mapper, context, path, adapter,
             else:
                 instance = mapper.class_manager.new_instance()
 
-            dict_ = attributes.instance_dict(instance)
-            state = attributes.instance_state(instance)
+            dict_ = instance_dict(instance)
+            state = instance_state(instance)
             state.key = identitykey
 
             # attach instance to session.
             state.session_id = context.session.hash_key
-            session_identity_map.add(state)
+            session_identity_map._add_unpresent(state, identitykey)
 
         if currentload or populate_existing:
             # state is being fully loaded, so populate.
@@ -451,9 +457,9 @@ def instance_processor(mapper, context, path, adapter,
             else:
                 populate_state(state, dict_, row, isnew, only_load_props)
 
-            if loaded_instance:
+            if loaded_instance and load_evt:
                 state.manager.dispatch.load(state, context)
-            elif isnew:
+            elif isnew and refresh_evt:
                 state.manager.dispatch.refresh(state, context, only_load_props)
 
         elif state in context.partials or state.unloaded or eager_populators:
index 5be2a657b95ea9436f1f4e11ad212d643025d0bb..768b73c21e90e40dbd72110993e55a454734fe7c 100644 (file)
@@ -559,12 +559,16 @@ class InstanceState(interfaces._InspectionAttr):
 
         for state, dict_ in iter:
             state.committed_state.clear()
-            InstanceState._pending_mutations._reset(state)
+
+            # inline of:
+            # InstanceState._pending_mutations._reset(state)
+            state.__dict__.pop('_pending_mutations', None)
 
             callables = state.callables
-            for key in list(callables):
-                if key in dict_ and callables[key] is state:
-                    del callables[key]
+            if callables:
+                for key in list(callables):
+                    if key in dict_ and callables[key] is state:
+                        del callables[key]
 
             if instance_dict and state.modified:
                 instance_dict._modified.discard(state)