diff --git a/config/alfresco/subsystems/fileServers/default/file-servers-context.xml b/config/alfresco/subsystems/fileServers/default/file-servers-context.xml index 0f10ada890..55bd006d7e 100644 --- a/config/alfresco/subsystems/fileServers/default/file-servers-context.xml +++ b/config/alfresco/subsystems/fileServers/default/file-servers-context.xml @@ -288,7 +288,10 @@ ${filesystem.cluster.name} - ${filesystem.cluster.config} + ${filesystem.cluster.configFile} + + + ${filesystem.cluster.debugFlags} diff --git a/config/alfresco/subsystems/fileServers/default/file-servers.properties b/config/alfresco/subsystems/fileServers/default/file-servers.properties index 8edf9ab029..20df2642a2 100644 --- a/config/alfresco/subsystems/fileServers/default/file-servers.properties +++ b/config/alfresco/subsystems/fileServers/default/file-servers.properties @@ -101,4 +101,11 @@ nfs.mountServerDebug=false # filesystem.cluster.enabled=false filesystem.cluster.name=AlfrescoFilesysCache -filesystem.cluster.config=Rhubarb +# Where to find the hazelcast config file +filesystem.cluster.configFile=not specified +# Hazelcast cluster debug flags +# Comma delimeted list of levels +# "StateCache", "Expire", "NearCache", "Oplock", "ByteLock", "FileAccess", "Membership", +# "Cleanup", "PerNode", "ClusterEntry", "ClusterMessage", "RemoteTask", "RemoteTiming", +# "Rename", "FileDataUpdate", "FileStatus" +filesystem.cluster.debugFlags= diff --git a/source/java/org/alfresco/filesys/AbstractServerConfigurationBean.java b/source/java/org/alfresco/filesys/AbstractServerConfigurationBean.java index 3680021153..39871651a4 100644 --- a/source/java/org/alfresco/filesys/AbstractServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/AbstractServerConfigurationBean.java @@ -442,22 +442,6 @@ public abstract class AbstractServerConfigurationBean extends ServerConfiguratio // Initialize the filesystems - try - { - // Process the Cluster configuration - processClusterConfig(); - - // Log the successful startup - - // logger.info("JLAN Cluster started"); - } - catch (Exception ex) - { - // Configuration error - - logger.error("Cluster configuration error, " + ex.getMessage(), ex); - } - try { // Process the core server configuration @@ -465,6 +449,9 @@ public abstract class AbstractServerConfigurationBean extends ServerConfiguratio // Process the security configuration processSecurityConfig(); + + // Process the Cluster configuration + processClusterConfig(); // Process the filesystems configuration processFilesystemsConfig(); diff --git a/source/java/org/alfresco/filesys/config/ClusterConfigBean.java b/source/java/org/alfresco/filesys/config/ClusterConfigBean.java index 5abf68318c..3de138f82a 100644 --- a/source/java/org/alfresco/filesys/config/ClusterConfigBean.java +++ b/source/java/org/alfresco/filesys/config/ClusterConfigBean.java @@ -29,6 +29,8 @@ public class ClusterConfigBean private boolean isClusterEnabled = false; private String configFile; private String clusterName; + private String debugFlags; + private int nearCacheTimeout; public void setClusterEnabled(boolean clusterEnabled) { @@ -59,4 +61,24 @@ public class ClusterConfigBean { return configFile; } + + public void setDebugFlags(String debugFlags) + { + this.debugFlags = debugFlags; + } + + public String getDebugFlags() + { + return debugFlags; + } + + public void setNearCacheTimeout(int nearCacheTimeout) + { + this.nearCacheTimeout = nearCacheTimeout; + } + + public int getNearCacheTimeout() + { + return nearCacheTimeout; + } } diff --git a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java index a09209ebea..9a1e375b08 100644 --- a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java @@ -35,13 +35,11 @@ import java.util.Enumeration; import java.util.List; import java.util.StringTokenizer; -import org.springframework.extensions.config.ConfigElement; import org.springframework.extensions.config.element.GenericConfigElement; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.AbstractServerConfigurationBean; import org.alfresco.filesys.alfresco.AlfrescoContext; import org.alfresco.filesys.alfresco.ExtendedDiskInterface; -import org.alfresco.filesys.alfresco.MultiTenantShareMapper; import org.alfresco.filesys.avm.AVMContext; import org.alfresco.filesys.avm.AVMDiskDriver; import org.alfresco.filesys.config.acl.AccessControlListBean; @@ -1650,12 +1648,24 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean ExtendedDiskInterface filesysDriver = getAvmDiskInterface(); DiskDeviceContext diskCtx = (DiskDeviceContext) filesystem; - - // Check if the filesystem uses the file state cache, if so then add to the file state reaper - StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); - standaloneCache.initializeCache( new GenericConfigElement( ""), this); - diskCtx.setStateCache(standaloneCache); - + if(clusterConfigBean != null && clusterConfigBean.getClusterEnabled()) + { + if(logger.isDebugEnabled()) + { + logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ diskCtx.getShareName()); + } + GenericConfigElement hazelConfig = createClusterConfig(diskCtx.getShareName()); + HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); + hazel.initializeCache(hazelConfig, this); + diskCtx.setStateCache(hazel); + } + else + { + // Check if the filesystem uses the file state cache, if so then add to the file state reaper + StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); + standaloneCache.initializeCache( new GenericConfigElement( ""), this); + diskCtx.setStateCache(standaloneCache); + } if ( diskCtx.hasStateCache()) { // Register the state cache with the reaper thread @@ -1687,28 +1697,9 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean { logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ filesysContext.getShareName()); } - - // initialise the hazelcast cache for this filesystem + GenericConfigElement hazelConfig = createClusterConfig(filesysContext.getShareName()); HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); - GenericConfigElement config = new GenericConfigElement("hazelcastStateCache"); - GenericConfigElement clusterNameCfg = new GenericConfigElement("clusterName"); - clusterNameCfg.setValue(clusterConfigBean.getClusterName()); - config.addChild(clusterNameCfg); - - GenericConfigElement topicNameCfg = new GenericConfigElement("clusterTopic"); - String topicName = filesysContext.getShareName(); - if(topicName == null || topicName.isEmpty()) - { - topicName="default"; - } - topicNameCfg.setValue(topicName); - config.addChild(topicNameCfg); - - GenericConfigElement debugCfg = new GenericConfigElement("cacheDebug"); - debugCfg.addAttribute("flags", "StateCache,Rename"); - config.addChild(debugCfg); - - hazel.initializeCache(config, this); + hazel.initializeCache(hazelConfig, this); filesysContext.setStateCache(hazel); } else @@ -2175,17 +2166,32 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean // Set the state cache, use a hard coded standalone cache for now FilesystemsConfigSection filesysConfig = (FilesystemsConfigSection) this.getConfigSection( FilesystemsConfigSection.SectionName); - if ( filesysConfig != null) { + if ( filesysConfig != null) + { - try { - - // Create a standalone state cache - StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); - standaloneCache.initializeCache( new GenericConfigElement( ""), this); - filesysConfig.addFileStateCache( diskCtx.getDeviceName(), standaloneCache); - diskCtx.setStateCache( standaloneCache); + try + { + if(clusterConfigBean != null && clusterConfigBean.getClusterEnabled()) + { + if(logger.isDebugEnabled()) + { + logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ diskCtx.getShareName()); + } + GenericConfigElement hazelConfig = createClusterConfig(diskCtx.getShareName()); + HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); + hazel.initializeCache(hazelConfig, this); + diskCtx.setStateCache(hazel); + } + else + { + // Create a standalone state cache + StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); + standaloneCache.initializeCache( new GenericConfigElement( ""), this); + filesysConfig.addFileStateCache( diskCtx.getDeviceName(), standaloneCache); + diskCtx.setStateCache( standaloneCache); + } - FileStateLockManager lockMgr = new FileStateLockManager(standaloneCache); + FileStateLockManager lockMgr = new FileStateLockManager(diskCtx.getStateCache()); diskCtx.setLockManager(lockMgr); diskCtx.setOpLockManager(lockMgr); } @@ -2197,43 +2203,22 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean } } - /** - * Initialise a runtime context - AVM - * - * TODO - what about desktop actions etc? - * - * @param diskCtx - */ - public void initialiseRuntimeContext(AVMContext diskCtx) - { - if (diskCtx.getStateCache() == null) { - - // Set the state cache, use a hard coded standalone cache for now - FilesystemsConfigSection filesysConfig = (FilesystemsConfigSection) this.getConfigSection( FilesystemsConfigSection.SectionName); - - if ( filesysConfig != null) { - - try { - - // Create a standalone state cache - StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); - standaloneCache.initializeCache( new GenericConfigElement( ""), this); - filesysConfig.addFileStateCache( diskCtx.getDeviceName(), standaloneCache); - diskCtx.setStateCache( standaloneCache); - } - catch ( InvalidConfigurationException ex) { - throw new AlfrescoRuntimeException( "Failed to initialize standalone state cache for " + diskCtx.getDeviceName()); - } - } - } - } - @Override protected void processClusterConfig() throws InvalidConfigurationException { - - // TODO - when should we close the config ? jlanClusterConfig.closeConfig(); + +// Done by org.alfresco.jlan.server.config.ServerConfiguration.closeConfiguration +// /** +// * Close the old hazelcast configuration +// */ +// ClusterConfigSection secConfig = (ClusterConfigSection) getConfigSection(ClusterConfigSection.SectionName); +// { +// if(secConfig != null) +// { +// secConfig.closeConfig(); +// } +// } if (clusterConfigBean == null || !clusterConfigBean.getClusterEnabled()) { @@ -2268,4 +2253,38 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean throw new InvalidConfigurationException("Unable to start filsystem cluster", e); } } + + + private GenericConfigElement createClusterConfig(String topicName) throws InvalidConfigurationException + { + GenericConfigElement config = new GenericConfigElement("hazelcastStateCache"); + GenericConfigElement clusterNameCfg = new GenericConfigElement("clusterName"); + clusterNameCfg.setValue(clusterConfigBean.getClusterName()); + config.addChild(clusterNameCfg); + + GenericConfigElement topicNameCfg = new GenericConfigElement("clusterTopic"); + if(topicName == null || topicName.isEmpty()) + { + topicName="default"; + } + topicNameCfg.setValue(topicName); + config.addChild(topicNameCfg); + + if(clusterConfigBean.getDebugFlags() != null) + { + GenericConfigElement debugCfg = new GenericConfigElement("cacheDebug"); + debugCfg.addAttribute("flags", clusterConfigBean.getDebugFlags()); + config.addChild(debugCfg); + } + + if(clusterConfigBean.getNearCacheTimeout() > 0) + { + GenericConfigElement nearCacheCfg = new GenericConfigElement("nearCache"); + nearCacheCfg.addAttribute("disable", Boolean.FALSE.toString()); + nearCacheCfg.addAttribute("timeout", Integer.toString(clusterConfigBean.getNearCacheTimeout())); + config.addChild(nearCacheCfg); + } + return config; + } + } diff --git a/source/java/org/alfresco/filesys/repo/FilesystemTransactionAdvice.java b/source/java/org/alfresco/filesys/repo/FilesystemTransactionAdvice.java index ae31252fbf..fdda5a45c2 100644 --- a/source/java/org/alfresco/filesys/repo/FilesystemTransactionAdvice.java +++ b/source/java/org/alfresco/filesys/repo/FilesystemTransactionAdvice.java @@ -20,8 +20,9 @@ package org.alfresco.filesys.repo; import java.io.IOException; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.jlan.server.SrvSession; +import org.alfresco.jlan.server.core.DeviceContextException; +import org.alfresco.jlan.server.filesys.IOControlNotImplementedException; +import org.alfresco.jlan.smb.SMBException; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.transaction.TransactionService; @@ -29,7 +30,16 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** - * An advice wrapper for an AlfrescoDiskDriver. + * An advice wrapper for an AlfrescoDiskDriver. Wraps the method call with a + * RetryingTransactionHandler. + *

+ * Needs to let the checked exceptions that are specified on the JLAN interfaces through. + * In particular must avoid wrapping JLAN's checked exceptions with an AlfrescoRuntimeException + * (so must throw IOException etc) + *

+ * @See DiskInterface + * @See IOControlHandler + * */ public class FilesystemTransactionAdvice implements MethodInterceptor { @@ -68,11 +78,23 @@ public class FilesystemTransactionAdvice implements MethodInterceptor { return methodInvocation.proceed(); } + catch (SMBException e) + { + throw new PropagatingException(e); + } + catch (IOControlNotImplementedException e) + { + throw new PropagatingException(e); + } catch (IOException e) { // Ensure original checked IOExceptions get propagated throw new PropagatingException(e); } + catch (DeviceContextException e) + { + throw new PropagatingException(e); + } } }; @@ -85,8 +107,17 @@ public class FilesystemTransactionAdvice implements MethodInterceptor } catch(PropagatingException pe) { - // Unwrap checked exceptions - throw (IOException) pe.getCause(); + Throwable t = pe.getCause(); + if(t != null) + { + if(t instanceof IOException) + { + // Unwrap checked exceptions + throw (IOException) pe.getCause(); + } + throw t; + } + throw pe; } } else @@ -105,16 +136,6 @@ public class FilesystemTransactionAdvice implements MethodInterceptor } } -// public void setDriver(AlfrescoDiskDriver driver) -// { -// this.driver = driver; -// } -// -// public AlfrescoDiskDriver getDriver() -// { -// return driver; -// } - public void setTransactionService(TransactionService transactionService) { this.transactionService = transactionService;