From: Mike Bayer Date: Mon, 19 May 2014 20:57:14 +0000 (-0400) Subject: - some inlining, speed up identity map X-Git-Tag: rel_1_0_0b1~440 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=474168bd884792b30b5312a18ad68f2563206952;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - some inlining, speed up identity map --- diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py index a91085d286..f9cd992892 100644 --- a/lib/sqlalchemy/orm/identity.py +++ b/lib/sqlalchemy/orm/identity.py @@ -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) diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index b79ea429c6..8fcace9be1 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -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: diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 5be2a657b9..768b73c21e 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -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)