ICU collators must not be used across threads

This commit is contained in:
Kovid Goyal 2022-04-24 14:08:46 +05:30
parent 559f787adf
commit b6662c2650
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
# Setup code {{{ # Setup code {{{
import codecs import codecs
import sys import sys
from functools import lru_cache import threading
from calibre.utils.config_base import prefs, tweaks from calibre.utils.config_base import prefs, tweaks
from calibre_extensions import icu as _icu from calibre_extensions import icu as _icu
@ -48,7 +48,9 @@ except:
del is_ascii del is_ascii
@lru_cache(maxsize=32) thread_local_collator_cache = threading.local()
def collator(strength=None, numeric=None, ignore_alternate_chars=None, upper_first=None): def collator(strength=None, numeric=None, ignore_alternate_chars=None, upper_first=None):
global _locale global _locale
if _locale is None: if _locale is None:
@ -57,7 +59,15 @@ def collator(strength=None, numeric=None, ignore_alternate_chars=None, upper_fir
else: else:
from calibre.utils.localization import get_lang from calibre.utils.localization import get_lang
_locale = get_lang() _locale = get_lang()
if strength is None and numeric is None and ignore_alternate_chars is None and upper_first is None: key = strength, numeric, ignore_alternate_chars, upper_first
try:
ans = thread_local_collator_cache.cache.get(key)
except AttributeError:
thread_local_collator_cache.cache = {}
ans = None
if ans is not None:
return ans
if all(x is None for x in key):
try: try:
ans = _icu.Collator(_locale) ans = _icu.Collator(_locale)
except Exception as e: except Exception as e:
@ -77,13 +87,17 @@ def collator(strength=None, numeric=None, ignore_alternate_chars=None, upper_fir
except AttributeError: except AttributeError:
pass # people running from source without latest binary pass # people running from source without latest binary
thread_local_collator_cache.cache[key] = ans
return ans return ans
def change_locale(locale=None): def change_locale(locale=None):
global _locale global _locale
_locale = locale _locale = locale
collator.cache_clear() try:
thread_local_collator_cache.cache.clear()
except AttributeError:
pass
def primary_collator(): def primary_collator():