diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-05-31 11:56:08 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-05-31 11:56:08 -0400 |
| commit | cfe9fadc61cfa05c71255fc0e447360199054ffc (patch) | |
| tree | 737dfbe4e262202a8a94f9335c558d519f843098 /lib/sqlalchemy | |
| parent | b42d679cf751d3311a45061c78371fc83bb1d5c2 (diff) | |
| download | sqlalchemy-cfe9fadc61cfa05c71255fc0e447360199054ffc.tar.gz | |
change the weakkeydict to be just an LRU cache. Add tests
for the "many combinations of UPDATE keys" issue.
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/util.py | 49 |
2 files changed, 57 insertions, 4 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 94e969bcc..4df51928b 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -43,6 +43,7 @@ _new_mappers = False _already_compiling = False _none_set = frozenset([None]) + # a list of MapperExtensions that will be installed in all mappers by default global_extensions = [] @@ -97,7 +98,9 @@ class Mapper(object): include_properties=None, exclude_properties=None, passive_updates=True, - eager_defaults=False): + eager_defaults=False, + _compiled_cache_size=100, + ): """Construct a new mapper. Mappers are normally constructed via the :func:`~sqlalchemy.orm.mapper` @@ -140,6 +143,7 @@ class Mapper(object): self._requires_row_aliasing = False self._inherits_equated_pairs = None self._memoized_values = {} + self._compiled_cache_size = _compiled_cache_size if allow_null_pks: util.warn_deprecated('the allow_null_pks option to Mapper() is ' @@ -1264,7 +1268,7 @@ class Mapper(object): @util.memoized_property def _compiled_cache(self): - return weakref.WeakKeyDictionary() + return util.LRUCache(self._compiled_cache_size) @util.memoized_property def _sorted_tables(self): @@ -1342,7 +1346,7 @@ class Mapper(object): cached_connections = util.PopulateDict( lambda conn:conn.execution_options( - compiled_cache=self._compiled_cache.setdefault(conn.engine, {}) + compiled_cache=self._compiled_cache )) # if session has a connection callable, @@ -1740,7 +1744,7 @@ class Mapper(object): tups = [] cached_connections = util.PopulateDict( lambda conn:conn.execution_options( - compiled_cache=self._compiled_cache.setdefault(conn.engine, {}) + compiled_cache=self._compiled_cache )) for state in _sort_states(states): diff --git a/lib/sqlalchemy/util.py b/lib/sqlalchemy/util.py index c2c85a4c9..4b04901a1 100644 --- a/lib/sqlalchemy/util.py +++ b/lib/sqlalchemy/util.py @@ -19,6 +19,7 @@ except ImportError: py3k = getattr(sys, 'py3kwarning', False) or sys.version_info >= (3, 0) jython = sys.platform.startswith('java') +win32 = sys.platform.startswith('win') if py3k: set_types = set @@ -1542,6 +1543,54 @@ class WeakIdentityMapping(weakref.WeakKeyDictionary): def _ref(self, object): return self._keyed_weakref(object, self._cleanup) +import time +if win32 or jython: + time_func = time.clock +else: + time_func = time.time + +class LRUCache(dict): + def __init__(self, capacity=100, threshold=.5): + self.capacity = capacity + self.threshold = threshold + + def __getitem__(self, key): + item = dict.__getitem__(self, key) + item[2] = time_func() + return item[1] + + def values(self): + return [i[1] for i in dict.values(self)] + + def setdefault(self, key, value): + if key in self: + return self[key] + else: + self[key] = value + return value + + def __setitem__(self, key, value): + item = dict.get(self, key) + if item is None: + item = [key, value, time_func()] + dict.__setitem__(self, key, item) + else: + item[1] = value + self._manage_size() + + def _manage_size(self): + while len(self) > self.capacity + self.capacity * self.threshold: + bytime = sorted(dict.values(self), + key=operator.itemgetter(2), + reverse=True) + for item in bytime[self.capacity:]: + try: + del self[item[0]] + except KeyError: + # if we couldnt find a key, most + # likely some other thread broke in + # on us. loop around and try again + break def warn(msg, stacklevel=3): if isinstance(msg, basestring): |
