summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-05-31 11:56:08 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2010-05-31 11:56:08 -0400
commitcfe9fadc61cfa05c71255fc0e447360199054ffc (patch)
tree737dfbe4e262202a8a94f9335c558d519f843098 /lib/sqlalchemy
parentb42d679cf751d3311a45061c78371fc83bb1d5c2 (diff)
downloadsqlalchemy-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.py12
-rw-r--r--lib/sqlalchemy/util.py49
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):