Overview

Currently, the only way for a command developer to modify cluster configuration is through internal methods or to manually edit the configuration xml file while the cluster is offline.
It can be expected that a module developer who create commands will need to modify the cluster configuration as well, therefore, we should expose a public API to retrieve or manipulate the cluster configuration persisted by the locator.

 

Background

The cache-1.0.xsd defines the permissible structure of the cluster config, currently represented in XML.
Developers can include their own cluster configuration elements in one of two places as defined in the cache-1.0.xsd: at the cache level or at the region level.
These accept any XML element, so long as the namespace does not match Geode's (i.e., {{http://geode.apache.org/schema/cache}}).

Goals

Anti-Goals

Approach

Proposal

As a minimum viable product, we would require only two methods: a getter and an updater.

public interface ConfigurationPersistenceService {
  /**
  * @param group The group to which the cluster configuration applies. default is "cluster"
  * @param additionalBindClass custom element classes created by other modules if present.
  * @return The cluster configuration for the specified group.
  */
  CacheConfig getCacheConfig(String group);
 
  /**
  * @param group The group to which the cluster configuration applies. default is "cluster"
  * @param mutator Specification of how the cluster configuration should be altered.
  * @param additionalBindClass custom element classes created by other modules if present.
  */
  void updateCacheConfig(String group, UnaryOperator<CacheConfig> mutator);
}


Intended Use:

Given an interface as the above, we would be able to implement, for instance, the CreateIndexCommand instead as

public class CreateIndexCommand implements SingleGfshCommand {
  private static final CreateIndexFunction createIndexFunction = new CreateIndexFunction();

  @CliCommand(value = CliStrings.CREATE_INDEX, help = CliStrings.CREATE_INDEX__HELP)
  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
      operation = ResourcePermission.Operation.MANAGE, target = ResourcePermission.Target.QUERY)
  public Result createIndex(...){
 
  Result result;
  final Set<DistributedMember> targetMembers = findMembers(group, memberNameOrID);

  if (targetMembers.isEmpty()) {
    return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
  }

  RegionConfig.Index index = new RegionConfig.Index();
  index.setName(indexName);
  index.setExpression(indexedExpression);
  index.setFromClause(regionPath);
  if (indexType == IndexType.PRIMARY_KEY) {
    index.setKeyIndex(true);
  } else {
    index.setKeyIndex(false);
    index.setType(indexType.getName());
  }

  List<CliFunctionResult> functionResults =
      executeAndGetFunctionResult(createIndexFunction, index, targetMembers);
  result = ResultBuilder.buildResult(functionResults);
  result.setConfigObject(index);
  return result;
}
 
@Override
public void updateClusterConfig(String group, CacheConfig config, Object element) {
  RegionConfig.Index index = (RegionConfig.Index) element;
  String regionPath = getValidRegionName(index.getFromClause(), config);

  RegionConfig regionConfig = config.findRegionConfiguration(regionPath);
  if (regionConfig == null) {
    throw new EntityNotFoundException("Region " + index.getFromClause() + " not found.");
  }
  regionConfig.getIndex().add(index);
}

 

Here, we declaratively build the RegionConfig.Index object we would like to add to the configuration.
On successfull creation, we search for the RegionConfig object to which the index configuration should belong and add this index to that array.
With the mutator defined, we execute (a concurrency-safe) update to the cluster configuration.

Long-term Goals

Resources