Dynamically Adding Data Structure Configuration on a Cluster

As described above, Hazelcast can be configured in a declarative or programmatic way; configuration must be completed before starting a Hazelcast member and this configuration cannot be altered at runtime, thus we refer to this as static configuration.

It is possible to dynamically add configuration for certain data structures at runtime; these can be added by invoking one of the Config.add*Config methods on the Config object obtained from a running member’s HazelcastInstance.getConfig() method. For example:

        Config config = new Config();
        MapConfig mapConfig = new MapConfig("sessions");
        config.addMapConfig(mapConfig);
        HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
        MapConfig noBackupsMap = new MapConfig("dont-backup").setBackupCount(0);
        instance.getConfig().addMapConfig(noBackupsMap);
You must invoke the add*Config method on the Hazelcast instance’s configuration object to add a configuration dynamically. In the above example, this is done with the instance.getConfig().addMapConfig(noBackupsMap); line. This submits the map configuration dynamically to all cluster members and also to members which join the cluster later.

Dynamic configuration elements must be fully configured before the invocation of add*Config method: at that point, the configuration object is delivered to every member of the cluster and added to each member’s dynamic configuration, so mutating the configuration object after the add*Config invocation does not have an effect.

As dynamically added data structure configuration is propagated across all cluster members, failures may occur due to conditions such as timeout and network partition. The configuration propagation mechanism internally retries adding the configuration whenever a membership change is detected. However if an exception is thrown from add*Config method, the configuration may have been partially propagated to some cluster members and adding the configuration should be retried by the user.

Adding a new dynamic configuration is supported for all add*Config methods except the following:

  • SplitBrainProtectionConfig: A new split-brain protection configuration cannot be dynamically added but other configuration can reference split-brain protections configured in the existing static configuration.

  • WanReplicationConfig: A new WAN replication configuration cannot be dynamically added, however existing static ones can be referenced from other configurations, e.g., a new dynamic MapConfig may include a WanReplicationRef to a statically configured WAN replication.

  • ListenerConfig: Listeners can be instead added at runtime via other API such as HazelcastInstance.getCluster().addMembershipListener and HazelcastInstance.getPartitionService().addMigrationListener.

Keep in mind that this feature also works for Hazelcast Java clients. See the following example:

HazelcastInstance client = HazelcastClient.newHazelcastClient();
MapConfig mCfg = new MapConfig("test");
mCfg.setTimeToLiveSeconds(15);
client.getConfig().addMapConfig(mCfg);
HazelcastClient.shutdownAll();
If your cluster has data structures with configurations added during runtime, those configurations are lost when a cluster restart occurs due to any reason since they are not persisted. This will be improved in future Hazelcast IMDG releases.

Handling Configuration Conflicts

Attempting to add a dynamic configuration, when a static configuration for the same element already exists, throws InvalidConfigurationException. For example, assuming we start a member with the following fragment in hazelcast.xml configuration:

<hazelcast>
    ...
    <map name="sessions">
        ...
    </map>
    ...
</hazelcast>

Then adding a dynamic configuration for a map with the name sessions throws a InvalidConfigurationException:

HazelcastInstance instance = Hazelcast.newHazelcastInstance();

MapConfig sessionsMapConfig = new MapConfig("sessions");

// this will throw ConfigurationException:
instance.getConfig().addMapConfig(sessionsMapConfig);

When attempting to add dynamic configuration for an element for which dynamic configuration has already been added, then if a configuration conflict is detected a InvalidConfigurationException is thrown. For example:

HazelcastInstance instance = Hazelcast.newHazelcastInstance();

MapConfig sessionsMapConfig = new MapConfig("sessions").setBackupCount(0);
instance.getConfig().addMapConfig(sessionsMapConfig);

MapConfig sessionsWithBackup = new MapConfig("sessions").setBackupCount(1);
// throws ConfigurationException because the new MapConfig conflicts with existing one
instance.getConfig().addMapConfig(sessionsWithBackup);

MapConfig sessionsWithoutBackup = new MapConfig("sessions").setBackupCount(0);
// does not throw exception: new dynamic config is equal to existing dynamic config of same name
instance.getConfig().addMapConfig(sessionsWithoutBackup);

Dynamic Data Structure Configuration and User Customizations

Dynamically added data structure configuration may reference user customizations, such as a user-provided MapLoader implementation referenced by a MapConfig. User customizations can be usually configured using either of the following:

  • by specifying a class or factory class name, e.g., MapStoreConfig.setClassName, and letting the Hazelcast members instantiate the object

  • by providing an existing instance, e.g., MapStoreConfig.setImplementation.

When dynamically adding new a data structure configuration with user customizations, take the following considerations into account:

  • For the user customizations submitted as a class name or factory class name, the referenced classes are resolved lazily. Therefore, they should be either already on each member’s local classpath or resolvable via user code deployment.

  • When the user customizations are submitted as instances (or similarly factory instances), the instances themselves have to be serializable. This is because the entire configuration needs to be sent over the network to all cluster members, and their classes have to be available on each member’s local classpath.