From 37911972ce33fe0eb89ca7f19d745e2f4732b731 Mon Sep 17 00:00:00 2001 From: Jan Vonka Date: Wed, 15 Apr 2009 09:43:03 +0000 Subject: [PATCH] MOB-659 (part 1 of 2) - improve namespace cache reset (should work even with null / cache) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13949 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/core-services-context.xml | 5 +- config/alfresco/ehcache-default.xml | 9 +- .../ehcache-custom.xml.sample.cluster | 16 - .../repo/dictionary/DictionaryDAOTest.java | 20 +- .../repo/dictionary/DiffModelTest.java | 43 +- .../repo/dictionary/NamespaceDAOImpl.java | 468 ++++++++++-------- .../alfresco/repo/dictionary/TestModel.java | 20 +- .../repo/policy/PolicyComponentTest.java | 22 +- 8 files changed, 313 insertions(+), 290 deletions(-) diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 346ba768f9..82aeb287c4 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -814,10 +814,7 @@ - - - - + diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml index 63f4f46e1e..a5b4647338 100644 --- a/config/alfresco/ehcache-default.xml +++ b/config/alfresco/ehcache-default.xml @@ -379,6 +379,7 @@ + - - + - - - - - - > urisCache = new EhCacheAdapter>(); - urisCache.setCache(urisEhCache); + Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L); + cacheManager.addCache(namespaceEhCache); + EhCacheAdapter namespaceCache = new EhCacheAdapter(); + namespaceCache.setCache(namespaceEhCache); - namespaceDAO.setUrisCache(urisCache); - - Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L); - cacheManager.addCache(prefixesEhCache); - EhCacheAdapter> prefixesCache = new EhCacheAdapter>(); - prefixesCache.setCache(prefixesEhCache); - - namespaceDAO.setPrefixesCache(prefixesCache); + namespaceDAO.setNamespaceDataCache(namespaceCache); } diff --git a/source/java/org/alfresco/repo/dictionary/DiffModelTest.java b/source/java/org/alfresco/repo/dictionary/DiffModelTest.java index 7babcdf93c..3bed6a386c 100755 --- a/source/java/org/alfresco/repo/dictionary/DiffModelTest.java +++ b/source/java/org/alfresco/repo/dictionary/DiffModelTest.java @@ -1,3 +1,27 @@ +/* + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ package org.alfresco.repo.dictionary; import java.io.ByteArrayInputStream; @@ -11,7 +35,7 @@ import net.sf.ehcache.CacheManager; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.cache.EhCacheAdapter; -import org.alfresco.repo.dictionary.M2ModelDiff; +import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceData; import org.alfresco.repo.tenant.SingleTServiceImpl; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.namespace.QName; @@ -784,19 +808,12 @@ public class DiffModelTest extends TestCase { CacheManager cacheManager = new CacheManager(); - Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L); - cacheManager.addCache(urisEhCache); - EhCacheAdapter> urisCache = new EhCacheAdapter>(); - urisCache.setCache(urisEhCache); + Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L); + cacheManager.addCache(namespaceEhCache); + EhCacheAdapter namespaceCache = new EhCacheAdapter(); + namespaceCache.setCache(namespaceEhCache); - namespaceDAO.setUrisCache(urisCache); - - Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L); - cacheManager.addCache(prefixesEhCache); - EhCacheAdapter> prefixesCache = new EhCacheAdapter>(); - prefixesCache.setCache(prefixesEhCache); - - namespaceDAO.setPrefixesCache(prefixesCache); + namespaceDAO.setNamespaceDataCache(namespaceCache); } public void testDeleteModel() diff --git a/source/java/org/alfresco/repo/dictionary/NamespaceDAOImpl.java b/source/java/org/alfresco/repo/dictionary/NamespaceDAOImpl.java index 16b453258b..2b327da2aa 100644 --- a/source/java/org/alfresco/repo/dictionary/NamespaceDAOImpl.java +++ b/source/java/org/alfresco/repo/dictionary/NamespaceDAOImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -55,10 +55,13 @@ public class NamespaceDAOImpl implements NamespaceDAO private Lock readLock = lock.readLock(); private Lock writeLock = lock.writeLock(); - // internal caches that are clusterable - private SimpleCache> urisCache; - private SimpleCache> prefixesCache; - + // Internal cache (clusterable) + private SimpleCache namespaceDataCache; + + // used to reset the cache + private ThreadLocal namespaceDataThreadLocal = new ThreadLocal(); + private ThreadLocal defaultNamespaceDataThreadLocal = new ThreadLocal(); + // Dependencies private TenantService tenantService; private DictionaryDAO dictionaryDAO; @@ -68,37 +71,24 @@ public class NamespaceDAOImpl implements NamespaceDAO { this.tenantService = tenantService; } - - public void setUrisCache(SimpleCache> urisCache) - { - this.urisCache = urisCache; - } - public void setPrefixesCache(SimpleCache> prefixesCache) + public void setNamespaceDataCache(SimpleCache namespaceDataCache) { - this.prefixesCache = prefixesCache; + this.namespaceDataCache = namespaceDataCache; } public void registerDictionary(DictionaryDAO dictionaryDAO) { this.dictionaryDAO = dictionaryDAO; } - + /** * Initialise empty namespaces */ public void init() { - String tenantDomain = getTenantDomain(); - - putUrisCtx(tenantDomain, new ArrayList()); - putPrefixesCtx(tenantDomain, new HashMap()); - - if (logger.isDebugEnabled()) - { - logger.debug("Empty namespaces initialised"); - } + initNamespace(getTenantDomain()); } /** @@ -107,9 +97,8 @@ public class NamespaceDAOImpl implements NamespaceDAO public void destroy() { String tenantDomain = getTenantDomain(); - - removeUrisCtx(tenantDomain); - removePrefixesCtx(tenantDomain); + + removeNamespaceData(tenantDomain); if (logger.isDebugEnabled()) { @@ -118,31 +107,90 @@ public class NamespaceDAOImpl implements NamespaceDAO } /** - * Resets the namespaces (by resetting the dictionary) + * Resets the namespaces (by re-initialising the dictionary) */ - private void reset() + private NamespaceData reset(String tenantDomain) { - if (logger.isDebugEnabled()) - { - logger.debug("Resetting namespaces ..."); - } - - if (dictionaryDAO == null) - { - // Unexpected - throw new AlfrescoRuntimeException("Dictionary should be registered in order to perform reset"); - } - else - { - dictionaryDAO.reset(); - } - - if (logger.isDebugEnabled()) - { - logger.debug("... resetting namespaces completed"); - } + if (dictionaryDAO == null) + { + // Unexpected + throw new AlfrescoRuntimeException("Dictionary should be registered in order to perform reset"); + } + + if (logger.isDebugEnabled()) + { + logger.debug("Resetting namespaces ..."); + } + + dictionaryDAO.init(); + + NamespaceData namespaceData = getNamespaceData(tenantDomain); + + if (logger.isDebugEnabled()) + { + logger.debug("... resetting namespaces completed"); + } + + return namespaceData; } - + + private NamespaceData initNamespace(String tenantDomain) + { + try + { + createNamespaceLocal(tenantDomain); + + NamespaceData namespaceData = initNamespaceData(tenantDomain); + + if (namespaceData == null) + { + // unexpected + throw new AlfrescoRuntimeException("Failed to init namespaceData " + tenantDomain); + } + + try + { + writeLock.lock(); + namespaceDataCache.put(tenantDomain, namespaceData); + } + finally + { + writeLock.unlock(); + } + + return namespaceData; + } + finally + { + try + { + readLock.lock(); + if (namespaceDataCache.get(tenantDomain) != null) + { + removeNamespaceLocal(tenantDomain); + } + } + finally + { + readLock.unlock(); + } + } + } + + private NamespaceData initNamespaceData(String tenantDomain) + { + getNamespaceData(tenantDomain).setUrisCache(new ArrayList()); + getNamespaceData(tenantDomain).setPrefixesCache(new HashMap()); + + if (logger.isDebugEnabled()) + { + logger.debug("Empty namespaces initialised"); + } + + return getNamespaceDataLocal(tenantDomain); + } + + /* (non-Javadoc) * @see org.alfresco.repo.ref.NamespacePrefixResolver#getURIs() */ @@ -175,8 +223,8 @@ public class NamespaceDAOImpl implements NamespaceDAO return Collections.unmodifiableCollection(urisFiltered); } } - - + + /* (non-Javadoc) * @see org.alfresco.repo.ref.NamespacePrefixResolver#getPrefixes() */ @@ -209,7 +257,7 @@ public class NamespaceDAOImpl implements NamespaceDAO return Collections.unmodifiableCollection(prefixesFiltered); } } - + /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.NamespaceDAO#addURI(java.lang.String) @@ -222,7 +270,7 @@ public class NamespaceDAOImpl implements NamespaceDAO } getUrisCtx().add(uri); } - + /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.NamespaceDAO#addPrefix(java.lang.String, java.lang.String) @@ -235,8 +283,8 @@ public class NamespaceDAOImpl implements NamespaceDAO } getPrefixesCtx().put(prefix, uri); } - - + + /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.NamespaceDAO#removeURI(java.lang.String) */ @@ -244,7 +292,7 @@ public class NamespaceDAOImpl implements NamespaceDAO { getUrisCtx().remove(uri); } - + /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.NamespaceDAO#removePrefix(java.lang.String) @@ -253,8 +301,8 @@ public class NamespaceDAOImpl implements NamespaceDAO { getPrefixesCtx().remove(prefix); } - - + + /* (non-Javadoc) * @see org.alfresco.repo.ref.NamespacePrefixResolver#getNamespaceURI(java.lang.String) */ @@ -280,7 +328,7 @@ public class NamespaceDAOImpl implements NamespaceDAO } } } - + /* (non-Javadoc) * @see org.alfresco.repo.ref.NamespacePrefixResolver#getPrefixes(java.lang.String) @@ -343,6 +391,120 @@ public class NamespaceDAOImpl implements NamespaceDAO } } + + // re-entrant (eg. via reset) + private NamespaceData getNamespaceData(String tenantDomain) + { + NamespaceData namespaceData = null; + try + { + // check cache first - return if set + readLock.lock(); + namespaceData = namespaceDataCache.get(tenantDomain); + + if (namespaceData != null) + { + return namespaceData; // return cached config + } + } + finally + { + readLock.unlock(); + } + + // check threadlocal second - return if set + namespaceData = getNamespaceDataLocal(tenantDomain); + if (namespaceData != null) + { + return namespaceData; // return local namespaceData + } + + // reset caches - may have been invalidated (e.g. in a cluster) + namespaceData = reset(tenantDomain); + + if (namespaceData == null) + { + // unexpected + throw new AlfrescoRuntimeException("Failed to get namespaceData " + tenantDomain); + } + + return namespaceData; + } + + // create threadlocal + private void createNamespaceLocal(String tenantDomain) + { + // create threadlocal, if needed + NamespaceData namespaceData = getNamespaceDataLocal(tenantDomain); + if (namespaceData == null) + { + namespaceData = new NamespaceData(tenantDomain); + + if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) + { + defaultNamespaceDataThreadLocal.set(namespaceData); + } + else + { + namespaceDataThreadLocal.set(namespaceData); + } + } + } + + // get threadlocal + private NamespaceData getNamespaceDataLocal(String tenantDomain) + { + NamespaceData namespaceData = null; + + if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) + { + namespaceData = this.defaultNamespaceDataThreadLocal.get(); + } + else + { + namespaceData = this.namespaceDataThreadLocal.get(); + } + + // check to see if domain switched (eg. during login) + if ((namespaceData != null) && (tenantDomain.equals(namespaceData.getTenantDomain()))) + { + return namespaceData; // return threadlocal, if set + } + + return null; + } + + // remove threadlocal + private void removeNamespaceLocal(String tenantDomain) + { + if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) + { + defaultNamespaceDataThreadLocal.set(null); // it's in the cache, clear the threadlocal + } + else + { + namespaceDataThreadLocal.set(null); // it's in the cache, clear the threadlocal + } + } + + private void removeNamespaceData(String tenantDomain) + { + try + { + writeLock.lock(); + if (namespaceDataCache.get(tenantDomain) != null) + { + namespaceDataCache.remove(tenantDomain); + } + + removeNamespaceLocal(tenantDomain); + } + finally + { + writeLock.unlock(); + } + } + /** * Get URIs from the cache (in the context of the current user's tenant domain) * @@ -361,82 +523,9 @@ public class NamespaceDAOImpl implements NamespaceDAO */ private List getUrisCtx(String tenantDomain) { - List uris = null; - try - { - readLock.lock(); - uris = urisCache.get(tenantDomain); - } - finally - { - readLock.unlock(); - } - - - if (uris == null) - { - reset(); // reset caches - may have been invalidated (e.g. in a cluster) - - try - { - readLock.lock(); - uris = urisCache.get(tenantDomain); - } - finally - { - readLock.unlock(); - } - - if (uris == null) - { - // unexpected - throw new AlfrescoRuntimeException("Failed to re-initialise urisCache " + tenantDomain); - } - } - return uris; + return getNamespaceData(tenantDomain).getUrisCache(); } - /** - * Put URIs into the cache - * - * @param tenantDomain - * @param uris - */ - private void putUrisCtx(String tenantDomain, List uris) - { - try - { - writeLock.lock(); - urisCache.put(tenantDomain, uris); - } - finally - { - writeLock.unlock(); - } - } - - /** - * Remove URIs from the cache - * - * @param tenantDomain - */ - private void removeUrisCtx(String tenantDomain) - { - try - { - writeLock.lock(); - if (urisCache.get(tenantDomain) != null) - { - urisCache.get(tenantDomain).clear(); - urisCache.remove(tenantDomain); - } - } - finally - { - writeLock.unlock(); - } - } - /** * Get prefixes from the cache * @@ -446,7 +535,7 @@ public class NamespaceDAOImpl implements NamespaceDAO { return getPrefixesCtx(getTenantDomain()); } - + /** * Get prefixes from the cache * @@ -455,81 +544,8 @@ public class NamespaceDAOImpl implements NamespaceDAO */ private Map getPrefixesCtx(String tenantDomain) { - Map prefixes = null; - try - { - readLock.lock(); - prefixes = prefixesCache.get(tenantDomain); - } - finally - { - readLock.unlock(); - } - - if (prefixes == null) - { - reset(); // reset caches - may have been invalidated (e.g. in a cluster) - - try - { - readLock.lock(); - prefixes = prefixesCache.get(tenantDomain); - } - finally - { - readLock.unlock(); - } - - if (prefixes == null) - { - // unexpected - throw new AlfrescoRuntimeException("Failed to re-initialise prefixesCache " + tenantDomain); - } - } - - return prefixes; - } - - /** - * Put prefixes into the cache - * - * @param tenantDomain - * @param prefixes - */ - private void putPrefixesCtx(String tenantDomain, Map prefixes) - { - try - { - writeLock.lock(); - prefixesCache.put(tenantDomain, prefixes); - } - finally - { - writeLock.unlock(); - } - } - - /** - * Remove prefixes from the cache - * - * @param tenantDomain - */ - private void removePrefixesCtx(String tenantDomain) - { - try - { - writeLock.lock(); - if (prefixesCache.get(tenantDomain) != null) - { - prefixesCache.get(tenantDomain).clear(); - prefixesCache.remove(tenantDomain); - } - } - finally - { - writeLock.unlock(); - } - } + return getNamespaceData(tenantDomain).getPrefixesCache(); + } /** * Local helper - returns tenant domain (or empty string if default non-tenant) @@ -538,4 +554,42 @@ public class NamespaceDAOImpl implements NamespaceDAO { return tenantService.getCurrentUserDomain(); } + + /* package */ class NamespaceData + { + private List urisCache; + private Map prefixesCache; + + private String tenantDomain; + + public NamespaceData(String tenantDomain) + { + this.tenantDomain = tenantDomain; + } + + public String getTenantDomain() + { + return tenantDomain; + } + + public List getUrisCache() + { + return urisCache; + } + + public void setUrisCache(List urisCache) + { + this.urisCache = urisCache; + } + + public Map getPrefixesCache() + { + return prefixesCache; + } + + public void setPrefixesCache(Map prefixesCache) + { + this.prefixesCache = prefixesCache; + } + } } diff --git a/source/java/org/alfresco/repo/dictionary/TestModel.java b/source/java/org/alfresco/repo/dictionary/TestModel.java index 689806c100..84e3ea9886 100644 --- a/source/java/org/alfresco/repo/dictionary/TestModel.java +++ b/source/java/org/alfresco/repo/dictionary/TestModel.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -32,6 +32,7 @@ import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import org.alfresco.repo.cache.EhCacheAdapter; +import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceData; import org.alfresco.repo.tenant.SingleTServiceImpl; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.namespace.QName; @@ -132,18 +133,11 @@ public class TestModel { CacheManager cacheManager = new CacheManager(); - Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L); - cacheManager.addCache(urisEhCache); - EhCacheAdapter> urisCache = new EhCacheAdapter>(); - urisCache.setCache(urisEhCache); + Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L); + cacheManager.addCache(namespaceEhCache); + EhCacheAdapter namespaceCache = new EhCacheAdapter(); + namespaceCache.setCache(namespaceEhCache); - namespaceDAO.setUrisCache(urisCache); - - Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L); - cacheManager.addCache(prefixesEhCache); - EhCacheAdapter> prefixesCache = new EhCacheAdapter>(); - prefixesCache.setCache(prefixesEhCache); - - namespaceDAO.setPrefixesCache(prefixesCache); + namespaceDAO.setNamespaceDataCache(namespaceCache); } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/policy/PolicyComponentTest.java b/source/java/org/alfresco/repo/policy/PolicyComponentTest.java index b07059741e..95ae4dbe0a 100644 --- a/source/java/org/alfresco/repo/policy/PolicyComponentTest.java +++ b/source/java/org/alfresco/repo/policy/PolicyComponentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,13 +27,13 @@ package org.alfresco.repo.policy; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; import junit.framework.TestCase; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import org.alfresco.repo.cache.EhCacheAdapter; +import org.alfresco.repo.cache.NullCache; import org.alfresco.repo.dictionary.DictionaryBootstrap; import org.alfresco.repo.dictionary.DictionaryComponent; import org.alfresco.repo.dictionary.DictionaryDAOImpl; @@ -112,23 +112,11 @@ public class PolicyComponentTest extends TestCase dictionaryDAO.setCompiledModelsCache(compileModelCache); } + @SuppressWarnings("unchecked") private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO) { - CacheManager cacheManager = new CacheManager(); - - Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L); - cacheManager.addCache(urisEhCache); - EhCacheAdapter> urisCache = new EhCacheAdapter>(); - urisCache.setCache(urisEhCache); - - namespaceDAO.setUrisCache(urisCache); - - Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L); - cacheManager.addCache(prefixesEhCache); - EhCacheAdapter> prefixesCache = new EhCacheAdapter>(); - prefixesCache.setCache(prefixesEhCache); - - namespaceDAO.setPrefixesCache(prefixesCache); + // note: unit tested here with null cache + namespaceDAO.setNamespaceDataCache(new NullCache()); } public void testJavaBehaviour()