Skip to content

Commit

Permalink
Merge pull request #1494 from hchiorean/MODE-2542
Browse files Browse the repository at this point in the history
MODE-2542 Adds the ability to cluster ModeShape repositories using dedicated JGroups channels
  • Loading branch information
Horia Chiorean committed Dec 8, 2015
2 parents c999030 + 1115c0a commit e75ebbc
Show file tree
Hide file tree
Showing 42 changed files with 491 additions and 97 deletions.
2 changes: 2 additions & 0 deletions deploy/jbossas/kit/jboss-wf9/org/modeshape/main/module.xml
Expand Up @@ -46,6 +46,8 @@
<!-- For naming ... -->
<module name="javax.api" export="true"/>
<module name="org.jboss.as.naming"/>
<!-- For clustering -->
<module name="org.wildfly.clustering.jgroups.api"/>
<!-- For security provider ... -->
<module name="javax.servlet.api"/>
<module name="javax.resource.api"/>
Expand Down
Expand Up @@ -264,11 +264,14 @@
<!-- A sample repository that uses the "sample" cache in the "modeshape" container. All content, binary values,
and indexes are stored within the server's data directory. This is the simplest way to configure a repository
that uses defaults for everything; feel free to change and specify other configuration options. -->
<repository name="sample" cache-name="sample" cache-config="modeshape/sample-ha-cache-config.xml" anonymous-roles="admin">
<repository name="sample" cache-name="sample" cache-config="modeshape/sample-ha-cache-config.xml"
anonymous-roles="admin"
cluster-name="sample-cluster" cluster-config="${jboss.server.config.dir}/modeshape/jgroups-config.xml">
<file-binary-storage path="modeshape/sample/binaries" relative-to="${java.tmp.dir}"/>
</repository>
<!-- A second sample repository that defines additional non-default components such as extra workspaces and sequencers. -->
<repository name="artifacts" cache-name="artifacts" cache-config="modeshape/artifacts-ha-cache-config.xml" anonymous-roles="admin">
<repository name="artifacts" cache-name="artifacts" cache-config="modeshape/artifacts-ha-cache-config.xml" anonymous-roles="admin"
cluster-name="artifacts-cluster" cluster-stack="tcp">
<index-providers>
<index-provider name="local" classname="local" path="modeshape/artifacts/indexes-${jboss.node.name}" relative-to="jboss.domain.data.dir" />
</index-providers>
Expand Down
3 changes: 3 additions & 0 deletions deploy/jbossas/modeshape-jbossas-cmis-war/pom.xml
Expand Up @@ -79,6 +79,9 @@
-->
<exclude>WEB-INF/lib/saaj-api-1.3.jar</exclude>
<exclude>WEB-INF/lib/saaj-impl-1.3.3.jar</exclude>
<exclude>WEB-INF/lib/antlr-runtime-3.2.jar</exclude>
<exclude>WEB-INF/lib/stax2-api-3.1.1.jar</exclude>
<exclude>WEB-INF/lib/woodstox-core-asl-4.2.0.jar</exclude>
</excludes>
</overlay>
</overlays>
Expand Down
4 changes: 4 additions & 0 deletions deploy/jbossas/modeshape-jbossas-subsystem/pom.xml
Expand Up @@ -64,6 +64,10 @@
<groupId>org.wildfly</groupId>
<artifactId>wildfly-security</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-clustering-jgroups-api</artifactId>
</dependency>
<dependency>
<groupId>org.picketbox</groupId>
<artifactId>picketbox-bare</artifactId>
Expand Down
Expand Up @@ -42,6 +42,7 @@
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.jboss.security.ISecurityManagement;
import org.jgroups.Channel;
import org.modeshape.common.collection.Problems;
import org.modeshape.common.util.DelegatingClassLoader;
import org.modeshape.common.util.StringUtil;
Expand All @@ -53,6 +54,7 @@
import org.modeshape.jcr.RepositoryConfiguration;
import org.modeshape.jcr.RepositoryConfiguration.FieldName;
import org.modeshape.jcr.RepositoryStatistics;
import org.wildfly.clustering.jgroups.ChannelFactory;

/**
* A <code>RepositoryService</code> instance is the service responsible for initializing a {@link JcrRepository} in the ModeShape
Expand All @@ -62,25 +64,24 @@ public class RepositoryService implements Service<JcrRepository>, Environment {

private static final Logger LOG = Logger.getLogger(RepositoryService.class.getPackage().getName());

private final InjectedValue<ModeShapeEngine> engineInjector = new InjectedValue<ModeShapeEngine>();
private final InjectedValue<BinaryStorage> binaryStorageInjector = new InjectedValue<BinaryStorage>();
private final InjectedValue<String> dataDirectoryPathInjector = new InjectedValue<String>();
private final InjectedValue<ModuleLoader> moduleLoaderInjector = new InjectedValue<ModuleLoader>();
private final InjectedValue<RepositoryStatistics> monitorInjector = new InjectedValue<RepositoryStatistics>();
private final InjectedValue<ISecurityManagement> securityManagementServiceInjector = new InjectedValue<ISecurityManagement>();
private final InjectedValue<ModeShapeEngine> engineInjector = new InjectedValue<>();
private final InjectedValue<BinaryStorage> binaryStorageInjector = new InjectedValue<>();
private final InjectedValue<String> dataDirectoryPathInjector = new InjectedValue<>();
private final InjectedValue<ModuleLoader> moduleLoaderInjector = new InjectedValue<>();
private final InjectedValue<RepositoryStatistics> monitorInjector = new InjectedValue<>();
private final InjectedValue<ChannelFactory> channelFactoryInjector = new InjectedValue<>();
private final InjectedValue<ISecurityManagement> securityManagementServiceInjector = new InjectedValue<>();

private final ConcurrentHashMap<String, CacheContainer> containers;
private final String cacheConfigRelativeTo;
private final String cacheConfig;
private final RepositoryConfiguration repositoryConfiguration;

private String journalPath;
private String journalRelativeTo;

public RepositoryService( RepositoryConfiguration repositoryConfiguration, String cacheConfig, String cacheConfigRelativeTo ) {
public RepositoryService(RepositoryConfiguration repositoryConfiguration, String cacheConfigRelativeTo) {
this.repositoryConfiguration = repositoryConfiguration;
this.containers = new ConcurrentHashMap<>();
this.cacheConfig = cacheConfig;
this.cacheConfigRelativeTo = cacheConfigRelativeTo;
}

Expand Down Expand Up @@ -165,6 +166,12 @@ public void shutdown() {
// Do nothing; this is the Environment's shutdown method
}

@Override
public Channel getChannel(String name) throws Exception {
final ChannelFactory channelFactory = channelFactoryInjector.getOptionalValue();
return channelFactory != null ? channelFactory.createChannel(name) : null;
}

public final String repositoryName() {
return repositoryConfiguration.getName();
}
Expand Down Expand Up @@ -603,6 +610,10 @@ public InjectedValue<ISecurityManagement> getSecurityManagementServiceInjector()
return securityManagementServiceInjector;
}

public InjectedValue<ChannelFactory> getChannelFactoryInjector() {
return channelFactoryInjector;
}

private ModuleLoader moduleLoader() {
return moduleLoaderInjector.getValue();
}
Expand Down
Expand Up @@ -52,6 +52,7 @@
import org.modeshape.jcr.RepositoryConfiguration;
import org.modeshape.jcr.RepositoryConfiguration.FieldName;
import org.modeshape.jcr.api.monitor.RepositoryMonitor;
import org.wildfly.clustering.jgroups.ChannelFactory;

public class AddRepository extends AbstractAddStepHandler {

Expand Down Expand Up @@ -114,6 +115,7 @@ protected void performRuntime( final OperationContext context,
final String cacheName = attribute(context, model, ModelAttributes.CACHE_NAME, repositoryName);
String infinispanConfig = attribute(context, model, ModelAttributes.CACHE_CONFIG, null);
String configRelativeTo = attribute(context, model, ModelAttributes.CONFIG_RELATIVE_TO).asString();
final String clusterName = attribute(context, model, ModelAttributes.CLUSTER_NAME, null);
final boolean enableMonitoring = attribute(context, model, ModelAttributes.ENABLE_MONITORING).asBoolean();
final String gcThreadPool = attribute(context, model, ModelAttributes.GARBAGE_COLLECTION_THREAD_POOL, null);
final String gcInitialTime = attribute(context, model, ModelAttributes.GARBAGE_COLLECTION_INITIAL_TIME, null);
Expand Down Expand Up @@ -168,7 +170,7 @@ protected void performRuntime( final OperationContext context,

// security
parseSecurity(context, model, configDoc);

// Now create the repository service that manages the lifecycle of the JcrRepository instance ...
RepositoryConfiguration repositoryConfig = new RepositoryConfiguration(configDoc, repositoryName);
String configRelativeToSystemProperty = System.getProperty(configRelativeTo);
Expand All @@ -178,7 +180,7 @@ protected void performRuntime( final OperationContext context,
if (!configRelativeTo.endsWith("/")) {
configRelativeTo = configRelativeTo + "/";
}
RepositoryService repositoryService = new RepositoryService(repositoryConfig, infinispanConfig, configRelativeTo);
RepositoryService repositoryService = new RepositoryService(repositoryConfig, configRelativeTo);
ServiceName repositoryServiceName = ModeShapeServiceNames.repositoryServiceName(repositoryName);

// Sequencing
Expand Down Expand Up @@ -227,8 +229,17 @@ protected void performRuntime( final OperationContext context,
docOpt.setNumber(FieldName.OPTIMIZATION_CHILD_COUNT_TOLERANCE, optTolerance.intValue());
}
}

if (!StringUtil.isBlank(clusterName)) {
final String clusterConfig = attribute(context, model, ModelAttributes.CLUSTER_CONFIG, null);
parseClustering(clusterName, clusterConfig, configDoc);
final String clusterStackName = attribute(context, model, ModelAttributes.CLUSTER_STACK, null);
if (!StringUtil.isBlank(clusterStackName)) {
repositoryServiceBuilder.addDependency(ServiceName.JBOSS.append("jgroups", "factory", clusterStackName),
ChannelFactory.class, repositoryService.getChannelFactoryInjector());
}
}


// Add the dependency to the Security Manager
repositoryServiceBuilder.addDependency(SecurityManagementService.SERVICE_NAME, ISecurityManagement.class,
repositoryService.getSecurityManagementServiceInjector());
Expand Down Expand Up @@ -301,6 +312,14 @@ protected void performRuntime( final OperationContext context,
newControllers.add(monitorBuilder.install());
}

private void parseClustering(String clusterName, String clusterConfig, EditableDocument configDoc) {
EditableDocument clustering = configDoc.getOrCreateDocument(FieldName.CLUSTERING);
clustering.setString(FieldName.CLUSTER_NAME, clusterName);
if (!StringUtil.isBlank(clusterConfig)) {
clustering.setString(FieldName.CLUSTER_CONFIGURATION, clusterConfig);
}
}

private void parseTextExtraction( ModelNode model, EditableDocument configDoc ) {
if (model.hasDefined(ModelKeys.TEXT_EXTRACTORS_THREAD_POOL_NAME)) {
EditableDocument extractors = configDoc.getOrCreateDocument(FieldName.TEXT_EXTRACTION);
Expand Down
Expand Up @@ -45,6 +45,9 @@ public enum Attribute {
DOCUMENT_OPTIMIZATION_CHILD_COUNT_TOLERANCE("document-optimization-child-count-tolerance"),
EVENT_BUS_SIZE("event-bus-size"),
ENABLE_MONITORING("enable-monitoring"),
CLUSTER_NAME("cluster-name"),
CLUSTER_STACK("cluster-stack"),
CLUSTER_CONFIG("cluster-config"),
GARBAGE_COLLECTION_THREAD_POOL("garbage-collection-thread-pool"),
GARBAGE_COLLECTION_INITIAL_TIME("garbage-collection-initial-time"),
GARBAGE_COLLECTION_INTERVAL("garbage-collection-interval"),
Expand Down
Expand Up @@ -149,6 +149,15 @@ private void parseRepository( final XMLExtendedStreamReader reader,
case ENABLE_MONITORING:
ModelAttributes.ENABLE_MONITORING.parseAndSetParameter(attrValue, repository, reader);
break;
case CLUSTER_STACK:
ModelAttributes.CLUSTER_STACK.parseAndSetParameter(attrValue, repository, reader);
break;
case CLUSTER_NAME:
ModelAttributes.CLUSTER_NAME.parseAndSetParameter(attrValue, repository, reader);
break;
case CLUSTER_CONFIG:
ModelAttributes.CLUSTER_CONFIG.parseAndSetParameter(attrValue, repository, reader);
break;
case SECURITY_DOMAIN:
ModelAttributes.SECURITY_DOMAIN.parseAndSetParameter(attrValue, repository, reader);
break;
Expand Down
Expand Up @@ -82,6 +82,9 @@ private void writeRepositoryConfiguration( XMLExtendedStreamWriter writer,
ModelAttributes.JNDI_NAME.marshallAsAttribute(repository, false, writer);
ModelAttributes.ENABLE_MONITORING.marshallAsAttribute(repository, false, writer);
ModelAttributes.SECURITY_DOMAIN.marshallAsAttribute(repository, false, writer);
ModelAttributes.CLUSTER_NAME.marshallAsAttribute(repository, false, writer);
ModelAttributes.CLUSTER_STACK.marshallAsAttribute(repository, false, writer);
ModelAttributes.CLUSTER_CONFIG.marshallAsAttribute(repository, false, writer);
writeAttributeAsList(writer, repository, ModelAttributes.ANONYMOUS_ROLES);
ModelAttributes.ANONYMOUS_USERNAME.marshallAsAttribute(repository, false, writer);
ModelAttributes.USE_ANONYMOUS_IF_AUTH_FAILED.marshallAsAttribute(repository, false, writer);
Expand Down
Expand Up @@ -237,6 +237,27 @@ public class ModelAttributes {
FieldName.MONITORING_ENABLED)
.build();

public static final SimpleAttributeDefinition CLUSTER_NAME = new MappedAttributeDefinitionBuilder(ModelKeys.CLUSTER_NAME,
ModelType.STRING).setXmlName(Attribute.CLUSTER_NAME.getLocalName())
.setAllowExpression(true)
.setAllowNull(true)
.setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
.build();

public static final SimpleAttributeDefinition CLUSTER_STACK = new MappedAttributeDefinitionBuilder(ModelKeys.CLUSTER_STACK,
ModelType.STRING).setXmlName(Attribute.CLUSTER_STACK.getLocalName())
.setAllowExpression(true)
.setAllowNull(true)
.setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
.build();

public static final SimpleAttributeDefinition CLUSTER_CONFIG = new MappedAttributeDefinitionBuilder(ModelKeys.CLUSTER_CONFIG,
ModelType.STRING).setXmlName(Attribute.CLUSTER_CONFIG.getLocalName())
.setAllowExpression(true)
.setAllowNull(true)
.setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
.build();

public static final SimpleAttributeDefinition GARBAGE_COLLECTION_THREAD_POOL = new MappedAttributeDefinitionBuilder(
ModelKeys.GARBAGE_COLLECTION_THREAD_POOL,
ModelType.STRING).setXmlName(Attribute.GARBAGE_COLLECTION_THREAD_POOL.getLocalName())
Expand Down Expand Up @@ -852,6 +873,7 @@ public class ModelAttributes {
public static final AttributeDefinition[] WEBAPP_ATTRIBUTES = {EXPLODED};

public static final AttributeDefinition[] REPOSITORY_ATTRIBUTES = {CACHE_NAME, CACHE_CONFIG, CONFIG_RELATIVE_TO, JNDI_NAME, ENABLE_MONITORING,
CLUSTER_NAME, CLUSTER_STACK, CLUSTER_CONFIG,
SECURITY_DOMAIN, ANONYMOUS_ROLES, ANONYMOUS_USERNAME, USE_ANONYMOUS_IF_AUTH_FAILED, NODE_TYPES, DEFAULT_WORKSPACE,
PREDEFINED_WORKSPACE_NAMES, ALLOW_WORKSPACE_CREATION, WORKSPACES_CACHE_SIZE, DEFAULT_INITIAL_CONTENT,
WORKSPACES_INITIAL_CONTENT, GARBAGE_COLLECTION_THREAD_POOL,
Expand Down
Expand Up @@ -45,6 +45,9 @@ public class ModelKeys {
static final String DOCUMENT_OPTIMIZATION_CHILD_COUNT_TOLERANCE = "document-optimization-child-count-tolerance";
static final String EVENT_BUS_SIZE = "event-bus-size";
static final String ENABLE_MONITORING = "enable-monitoring";
static final String CLUSTER_NAME = "cluster-name";
static final String CLUSTER_STACK = "cluster-stack";
static final String CLUSTER_CONFIG = "cluster-config";
static final String GARBAGE_COLLECTION_THREAD_POOL = "garbage-collection-thread-pool";
static final String GARBAGE_COLLECTION_INITIAL_TIME = "garbage-collection-initial-time";
static final String GARBAGE_COLLECTION_INTERVAL = "garbage-collection-interval";
Expand Down
Expand Up @@ -81,6 +81,9 @@ modeshape.repository.journal-max-days-to-keep-records = The maximum number of da
modeshape.repository.journal-async-writes = Whether writes to disk should be done asynchronously or not.
modeshape.repository.journal-gc-thread-pool = Name of the thread pool that should be used for removing older journal entries.
modeshape.repository.journal-gc-initial-time = The local time that the first garbage collection process should be run.
modeshape.repository.cluster-name = Defines the name of the communication channel used by this and other clustered repositories.
modeshape.repository.cluster-stack = Defines the JGroups stack used by the repository when clustered.
modeshape.repository.cluster-config = Defines the JGroups configuration file that can be used alternatively to the cluster-stack param

# Sequencer
modeshape.repository.sequencers-thread-pool-name = The name of the thread pool that generates sequencing threads
Expand Down

0 comments on commit e75ebbc

Please sign in to comment.