diff --git a/src/jrd/unicode_util.cpp b/src/jrd/unicode_util.cpp index ae5bca8895..4bc5c548b6 100644 --- a/src/jrd/unicode_util.cpp +++ b/src/jrd/unicode_util.cpp @@ -77,14 +77,14 @@ public: minorVersion(aMinorVersion), inModule(NULL), ucModule(NULL), - ciAiTrans(NULL) + ciAiTransCache(*getDefaultMemoryPool()) { } ~ICU() { - if (ciAiTrans) - utransClose(ciAiTrans); + while (ciAiTransCache.hasData()) + utransClose(ciAiTransCache.pop()); delete ucModule; delete inModule; @@ -108,12 +108,41 @@ public: module->findSymbol(symbol, ptr); } + UTransliterator* getCiAiTransliterator() + { + ciAiTransCacheMutex.enter(); + UTransliterator* ret; + + if (!ciAiTransCache.isEmpty()) + { + ret = ciAiTransCache.pop(); + ciAiTransCacheMutex.leave(); + } + else + { + ciAiTransCacheMutex.leave(); + + UErrorCode errorCode = U_ZERO_ERROR; + ret = utransOpen("Any-Upper; NFD; [:Nonspacing Mark:] Remove; NFC", + UTRANS_FORWARD, NULL, 0, NULL, &errorCode); + } + + return ret; + } + + void releaseCiAiTransliterator(UTransliterator* trans) + { + MutexLockGuard guard(ciAiTransCacheMutex); + ciAiTransCache.push(trans); + } + int majorVersion; int minorVersion; ModuleLoader::Module* inModule; ModuleLoader::Module* ucModule; UVersionInfo collVersion; - UTransliterator* ciAiTrans; + Mutex ciAiTransCacheMutex; + Array ciAiTransCache; void (U_EXPORT2 *uInit)(UErrorCode* status); void (U_EXPORT2 *uVersionToString)(UVersionInfo versionArray, char* versionString); @@ -146,9 +175,6 @@ public: int32_t rulesLength, /* -1 if null-terminated */ UParseError* parseError, /* may be Null */ UErrorCode* status); - UTransliterator* (U_EXPORT2 *utransClone)( - const UTransliterator* trans, - UErrorCode* status); void (U_EXPORT2 *utransTransUChars)( const UTransliterator* trans, UChar* text, @@ -893,7 +919,6 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const Firebird::string& icuVersion, icu->getEntryPoint("ucol_strcoll", icu->inModule, icu->ucolStrColl); icu->getEntryPoint("ucol_getVersion", icu->inModule, icu->ucolGetVersion); icu->getEntryPoint("utrans_open", icu->inModule, icu->utransOpen); - icu->getEntryPoint("utrans_clone", icu->inModule, icu->utransClone); icu->getEntryPoint("utrans_close", icu->inModule, icu->utransClose); icu->getEntryPoint("utrans_transUChars", icu->inModule, icu->utransTransUChars); @@ -920,15 +945,6 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const Firebird::string& icuVersion, } } - icu->ciAiTrans = icu->utransOpen("Any-Upper; NFD; [:Nonspacing Mark:] Remove; NFC", - UTRANS_FORWARD, NULL, 0, NULL, &status); - if (!icu->ciAiTrans) - { - gds__log("utransOpen failed"); - delete icu; - continue; - } - UCollator* collator = icu->ucolOpen("", &status); if (!collator) { @@ -1266,20 +1282,18 @@ ULONG UnicodeUtil::Utf16Collation::canonical(ULONG srcLen, const USHORT* src, UL memcpy(upperStr.getBuffer(srcLen / sizeof(USHORT)), src, srcLen); - // ASF: We cannot use a single transliterator simultaneously in multiple threads, - // but the creation is expensive. It's much faster to clone a pre-created one. - UErrorCode errorCode = U_ZERO_ERROR; - UTransliterator* trans = icu->utransClone(icu->ciAiTrans, &errorCode); + UTransliterator* trans = icu->getCiAiTransliterator(); - if (errorCode <= 0) + if (trans) { const int32_t capacity = upperStr.getCount(); int32_t len = srcLen / sizeof(USHORT); int32_t limit = len; + UErrorCode errorCode = U_ZERO_ERROR; icu->utransTransUChars(trans, reinterpret_cast(upperStr.begin()), &len, capacity, 0, &limit, &errorCode); - icu->utransClose(trans); + icu->releaseCiAiTransliterator(trans); len *= sizeof(USHORT); if (ULONG(len) > dstLen)