MNT-24708 - Set messagesCache and loadedBundlesCache as local (#3026)

* In a cluster env these caches were always invalidating the other nodes loaded bundles, forcing them to reload
* Only resourceBundlesNamesCache should be invalidating to be able to force the cache reset if a bundle is added, removed or reloaded dynamically
* On unregister of a resource bundle, the cache wasn't being explicitly updated, so it was not invalidating the cache on the other nodes.
This commit is contained in:
Eva Vasques
2024-11-07 18:03:52 +00:00
committed by GitHub
parent e99905efbd
commit 2904535d40
2 changed files with 68 additions and 59 deletions

View File

@@ -1,28 +1,28 @@
/* /*
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2016 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.repo.i18n; package org.alfresco.repo.i18n;
import java.io.BufferedReader; import java.io.BufferedReader;
@@ -204,13 +204,11 @@ public class MessageServiceImpl implements MessageService
{ {
if (! tenantResourceBundleBaseNames.contains(resBundlePath)) if (! tenantResourceBundleBaseNames.contains(resBundlePath))
{ {
tenantResourceBundleBaseNames.add(resBundlePath); tenantResourceBundleBaseNames.add(resBundlePath);
putResourceBundleBaseNames(tenantDomain, tenantResourceBundleBaseNames); reloadResourceBundles(tenantResourceBundleBaseNames);
} }
logger.info("Registered message bundle '" + resBundlePath + "'"); logger.info("Registered message bundle '" + resBundlePath + "'");
clearLoadedResourceBundles(tenantDomain); // force re-load of message cache
} }
finally finally
{ {
@@ -288,61 +286,64 @@ public class MessageServiceImpl implements MessageService
Map<Locale, Set<String>> loadedResourceBundlesForAllLocales; Map<Locale, Set<String>> loadedResourceBundlesForAllLocales;
Map<Locale, Map<String, String>> cachedMessagesForAllLocales; Map<Locale, Map<String, String>> cachedMessagesForAllLocales;
Set<String> resourceBundleBaseNamesForAllLocales; Set<String> resourceBundleBaseNamesForAllLocales;
String tenantDomain = getTenantDomain(); String tenantDomain = getTenantDomain();
LockHelper.tryLock(readLock, tryLockTimeout, "getting loaded resource bundles, messages and base names in 'MessageServiceImpl.unregisterResourceBundle()'"); LockHelper.tryLock(readLock, tryLockTimeout,
"getting loaded resource bundles, messages and base names in 'MessageServiceImpl.unregisterResourceBundle()'");
try try
{ {
// all locales // all locales
loadedResourceBundlesForAllLocales = getLoadedResourceBundles(tenantDomain, false); loadedResourceBundlesForAllLocales = getLoadedResourceBundles(tenantDomain, false);
cachedMessagesForAllLocales = getMessages(tenantDomain, false); cachedMessagesForAllLocales = getMessages(tenantDomain, false);
resourceBundleBaseNamesForAllLocales = getResourceBundleBaseNames(tenantDomain, false, true); resourceBundleBaseNamesForAllLocales = getResourceBundleBaseNames(tenantDomain, false, true);
} }
finally finally
{ {
readLock.unlock(); readLock.unlock();
} }
LockHelper.tryLock(writeLock, tryLockTimeout, "removing resource bundle by path in 'MessageServiceImpl.unregisterResourceBundle()'"); LockHelper.tryLock(writeLock, tryLockTimeout,
"removing resource bundle by path in 'MessageServiceImpl.unregisterResourceBundle()'");
try try
{ {
// unload resource bundles for each locale (by tenant, if applicable) // unload resource bundles for each locale (by tenant, if applicable)
if ((loadedResourceBundlesForAllLocales != null) && (cachedMessagesForAllLocales != null)) if ((loadedResourceBundlesForAllLocales != null) && (cachedMessagesForAllLocales != null))
{ {
Iterator<Locale> itr = loadedResourceBundlesForAllLocales.keySet().iterator(); Iterator<Locale> itr = loadedResourceBundlesForAllLocales.keySet().iterator();
while (itr.hasNext()) while (itr.hasNext())
{ {
Locale locale = itr.next(); Locale locale = itr.next();
Set<String> loadedBundles = loadedResourceBundlesForAllLocales.get(locale); Set<String> loadedBundles = loadedResourceBundlesForAllLocales.get(locale);
Map<String, String> props = cachedMessagesForAllLocales.get(locale); Map<String, String> props = cachedMessagesForAllLocales.get(locale);
if ((loadedBundles != null) && (props != null)) if ((loadedBundles != null) && (props != null))
{ {
if (loadedBundles.contains(resBundlePath)) if (loadedBundles.contains(resBundlePath))
{ {
ResourceBundle resourcebundle = null; ResourceBundle resourcebundle = null;
int idx1 = resBundlePath.indexOf(StoreRef.URI_FILLER); int idx1 = resBundlePath.indexOf(StoreRef.URI_FILLER);
if (idx1 != -1) if (idx1 != -1)
{ {
// load from repository // load from repository
int idx2 = resBundlePath.indexOf("/", idx1+3); int idx2 = resBundlePath.indexOf("/", idx1 + 3);
String store = resBundlePath.substring(0, idx2); String store = resBundlePath.substring(0, idx2);
String path = resBundlePath.substring(idx2); String path = resBundlePath.substring(idx2);
StoreRef storeRef = tenantService.getName(new StoreRef(store)); StoreRef storeRef = tenantService.getName(new StoreRef(store));
try try
{ {
resourcebundle = getRepoResourceBundle(storeRef, path, locale); resourcebundle = getRepoResourceBundle(storeRef, path, locale);
} }
catch (IOException ioe) catch (IOException ioe)
{ {
throw new AlfrescoRuntimeException("Failed to read message resource bundle from repository " + resBundlePath + " : " + ioe); throw new AlfrescoRuntimeException("Failed to read message resource bundle from repository "
+ resBundlePath + " : " + ioe);
} }
} }
else else
@@ -350,7 +351,7 @@ public class MessageServiceImpl implements MessageService
// load from classpath // load from classpath
resourcebundle = ResourceBundle.getBundle(resBundlePath, locale); resourcebundle = ResourceBundle.getBundle(resBundlePath, locale);
} }
if (resourcebundle != null) if (resourcebundle != null)
{ {
// unload from the cached messages // unload from the cached messages
@@ -361,21 +362,20 @@ public class MessageServiceImpl implements MessageService
props.remove(key); props.remove(key);
} }
} }
loadedBundles.remove(resBundlePath); loadedBundles.remove(resBundlePath);
} }
} }
} }
} }
// unregister resource bundle // unregister resource bundle
if (resourceBundleBaseNamesForAllLocales != null) if (resourceBundleBaseNamesForAllLocales != null)
{ {
resourceBundleBaseNamesForAllLocales.remove(resBundlePath); resourceBundleBaseNamesForAllLocales.remove(resBundlePath);
reloadResourceBundles(resourceBundleBaseNamesForAllLocales);
logger.info("Unregistered message bundle '" + resBundlePath + "'"); logger.info("Unregistered message bundle '" + resBundlePath + "'");
} }
clearLoadedResourceBundles(tenantDomain); // force re-load of message cache
} }
finally finally
{ {
@@ -383,6 +383,14 @@ public class MessageServiceImpl implements MessageService
} }
} }
private void reloadResourceBundles(Set<String> newResourceBundles)
{
logger.debug("Reloading message bundles ...");
String tenantDomain = getTenantDomain();
putResourceBundleBaseNames(tenantDomain, newResourceBundles);
clearLoadedResourceBundles(tenantDomain); // force re-load of message cache
}
/** /**
* Get the messages for a locale. * Get the messages for a locale.
* <p> * <p>
@@ -465,7 +473,7 @@ public class MessageServiceImpl implements MessageService
Set<String> resBundleBaseNames = getResourceBundleBaseNames(tenantDomain, true, false); Set<String> resBundleBaseNames = getResourceBundleBaseNames(tenantDomain, true, false);
int count = 0; int count = 0;
// load resource bundles for given locale (by tenant, if applicable) // load resource bundles for given locale (by tenant, if applicable)
for (String resBundlePath : resBundleBaseNames) for (String resBundlePath : resBundleBaseNames)
{ {
@@ -474,24 +482,25 @@ public class MessageServiceImpl implements MessageService
ResourceBundle resourcebundle = null; ResourceBundle resourcebundle = null;
int idx1 = resBundlePath.indexOf(StoreRef.URI_FILLER); int idx1 = resBundlePath.indexOf(StoreRef.URI_FILLER);
if (idx1 != -1) if (idx1 != -1)
{ {
// load from repository // load from repository
int idx2 = resBundlePath.indexOf("/", idx1+3); int idx2 = resBundlePath.indexOf("/", idx1 + 3);
String store = resBundlePath.substring(0, idx2); String store = resBundlePath.substring(0, idx2);
String path = resBundlePath.substring(idx2); String path = resBundlePath.substring(idx2);
StoreRef storeRef = tenantService.getName(new StoreRef(store)); StoreRef storeRef = tenantService.getName(new StoreRef(store));
try try
{ {
resourcebundle = getRepoResourceBundle(storeRef, path, locale); resourcebundle = getRepoResourceBundle(storeRef, path, locale);
} }
catch (IOException ioe) catch (IOException ioe)
{ {
throw new AlfrescoRuntimeException("Failed to read message resource bundle from repository " + resBundlePath + " : " + ioe); throw new AlfrescoRuntimeException(
"Failed to read message resource bundle from repository " + resBundlePath + " : " + ioe);
} }
} }
else else
@@ -508,13 +517,13 @@ public class MessageServiceImpl implements MessageService
String key = enumKeys.nextElement(); String key = enumKeys.nextElement();
props.put(key, resourcebundle.getString(key)); props.put(key, resourcebundle.getString(key));
} }
loadedBundles.add(resBundlePath); loadedBundles.add(resBundlePath);
count++; count++;
} }
} }
} }
logger.info("Message bundles (x " + count + ") loaded for locale " + locale); logger.info("Message bundles (x " + count + ") loaded for locale " + locale);
} }
finally finally

View File

@@ -394,7 +394,7 @@ cache.loadedResourceBundlesSharedCache.tx.statsEnabled=${caches.tx.statsEnabled}
cache.loadedResourceBundlesSharedCache.maxItems=1000 cache.loadedResourceBundlesSharedCache.maxItems=1000
cache.loadedResourceBundlesSharedCache.timeToLiveSeconds=0 cache.loadedResourceBundlesSharedCache.timeToLiveSeconds=0
cache.loadedResourceBundlesSharedCache.maxIdleSeconds=0 cache.loadedResourceBundlesSharedCache.maxIdleSeconds=0
cache.loadedResourceBundlesSharedCache.cluster.type=invalidating cache.loadedResourceBundlesSharedCache.cluster.type=local
cache.loadedResourceBundlesSharedCache.backup-count=1 cache.loadedResourceBundlesSharedCache.backup-count=1
cache.loadedResourceBundlesSharedCache.eviction-policy=LRU cache.loadedResourceBundlesSharedCache.eviction-policy=LRU
cache.loadedResourceBundlesSharedCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy cache.loadedResourceBundlesSharedCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
@@ -405,7 +405,7 @@ cache.messagesSharedCache.tx.statsEnabled=${caches.tx.statsEnabled}
cache.messagesSharedCache.maxItems=1000 cache.messagesSharedCache.maxItems=1000
cache.messagesSharedCache.timeToLiveSeconds=0 cache.messagesSharedCache.timeToLiveSeconds=0
cache.messagesSharedCache.maxIdleSeconds=0 cache.messagesSharedCache.maxIdleSeconds=0
cache.messagesSharedCache.cluster.type=invalidating cache.messagesSharedCache.cluster.type=local
cache.messagesSharedCache.backup-count=1 cache.messagesSharedCache.backup-count=1
cache.messagesSharedCache.eviction-policy=LRU cache.messagesSharedCache.eviction-policy=LRU
cache.messagesSharedCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy cache.messagesSharedCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy