Skip to content

Commit

Permalink
Add an RLock around the Locale cache.
Browse files Browse the repository at this point in the history
Refs #31 (#31)
  • Loading branch information
akx committed Dec 29, 2015
1 parent 633b52c commit 2d8a5a8
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
18 changes: 15 additions & 3 deletions babel/_memoized.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,27 @@ class Memoized(type):
def __new__(mcs, name, bases, dict):
if "_cache" not in dict:
dict["_cache"] = {}
if "_cache_lock" not in dict:
dict["_cache_lock"] = None
return type.__new__(mcs, name, bases, dict)

def __memoized_init__(cls, *args, **kwargs):
lock = cls._cache_lock
if hasattr(cls, "_get_memo_key"):
key = cls._get_memo_key(args, kwargs)
else:
key = (args or None, frozenset(kwargs.items()) or None)
if key not in cls._cache:
cls._cache[key] = type.__call__(cls, *args, **kwargs)
return cls._cache[key]

try:
return cls._cache[key]
except KeyError:
try:
if lock:
lock.acquire()
inst = cls._cache[key] = type.__call__(cls, *args, **kwargs)
return inst
finally:
if lock:
lock.release()

__call__ = __memoized_init__ # This aliasing makes tracebacks more understandable.
5 changes: 4 additions & 1 deletion babel/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
:copyright: (c) 2013 by the Babel Team.
:license: BSD, see LICENSE for more details.
"""

import os
import threading

from babel import localedata
from babel._compat import pickle, string_types, with_metaclass
Expand Down Expand Up @@ -125,6 +125,9 @@ class Locale(with_metaclass(Memoized)):
#: The dictionary used by the locale cache metaclass.
_cache = {}

#: The lock used for the cache metaclass.
_cache_lock = threading.RLock()

@staticmethod
def _get_memo_key(args, kwargs):
# Getter for a cache key for the Memoized metaclass.
Expand Down

0 comments on commit 2d8a5a8

Please sign in to comment.