8.2. Region Activation/Inactivation
The basic API discussed above is helpful, but in situations where applications with different classloaders are sharing a cache, the lifecycle of those applications will typically be different from that of the cache. The result of this is that it is difficult or impossible to register all required classloaders before a cache is started. For example, consider the following scenario:
TreeCache on machine A starts.
On A a classloader is registered under FQN /x.
Machine B starts, so TreeCache on B starts.
An object is put in the machine A cache under FQN /x/1.
Replication to B fails, as the required classloader is not yet registered.
On B a classloader is registered under FQN /x, but too late to prevent the replication error.
Furthermore, if any objects had been added to server A before server B was started, the initial transfer of state from A to B would have failed as well, as B would not be able to unmarshal the transferred objects.
To resolve this problem, if region-based marshalling is used a cache instance can be configured to ignore replication events for a portion of the tree. That portion of the tree is considered "inactive". After the needed classloader has been registered, the portion of the tree can be "activated". Activation causes the following events to occur:
Any existing state for that portion of the tree is transferred from another node in the cluster and integrated into the local tree.
TreeCacheMarshaller begins normal handling of replication traffic related to the portion of the tree.
In addition to the basic marshalling related API discussed above, TreeCache exposes the following API related to activating and inactivating portions of the cache:
/**
* Sets whether the entire tree is inactive upon startup, only responding
* to replication messages after {@link #activateRegion(String)} is
* called to activate one or more parts of the tree.
* <p>
* This property is only relevant if {@link #getUseRegionBasedMarshalling()} is
* true.
*
*/
public void setInactiveOnStartup(boolean inactiveOnStartup);
/**
* Gets whether the entire tree is inactive upon startup, only responding
* to replication messages after {@link #activateRegion(String)} is
* called to activate one or more parts of the tree.
* <p>
* This property is only relevant if {@link #getUseRegionBasedMarshalling()} is
* true.
*/
public boolean isInactiveOnStartup();
/**
* Causes the cache to transfer state for the subtree rooted at
* subtreeFqn and to begin accepting replication messages
* for that subtree.
*
* NOTE: This method will cause the creation of a node
* in the local tree at subtreeFqn whether or not that
* node exists anywhere else in the cluster. If the node does not exist
* elsewhere, the local node will be empty. The creation of this node will
* not be replicated.
*
* @param subtreeFqn Fqn string indicating the uppermost node in the
* portion of the tree that should be activated.
*
* @throws RegionNotEmptyException if the node subtreeFqn
* exists and has either data or children
*
* @throws IllegalStateException if useRegionBasedMarshalling is false
*/
public void activateRegion(String subtreeFqn)
throws RegionNotEmptyException, RegionNameConflictException, CacheException;
/**
* Causes the cache to stop accepting replication events for the subtree
* rooted at subtreeFqn and evict all nodes in that subtree.
*
* @param subtreeFqn Fqn string indicating the uppermost node in the
* portion of the tree that should be activated.
* @throws RegionNameConflictException if subtreeFqn indicates
* a node that is part of another subtree that is being specially
* managed (either by activate/inactiveRegion()
* or by registerClassLoader())
* @throws CacheException if there is a problem evicting nodes
*
* @throws IllegalStateException if useRegionBasedMarshalling is false
*/
public void inactivateRegion(String subtreeFqn) throws RegionNameConflictException,
CacheException;
Property InactiveOnStartup controls whether the entire cache should be considered inactive when the cache starts. In most use cases where region activation is needed, this property would be set to true. This property should be set as part of normal cache configuration, typically in the cache's XML configuration file:
<attribute name="InactiveOnStartup">true</attribute>
When InactiveOnStartup is set to true, no state transfer will be performed on startup, even if property FetchInMemoryState is true.
When activateRegion() is invoked, each node in the cluster will be queried to see if it has active state for that portion of the tree. If one does, it will return the current state, which will then be integrated into the tree. Once state is transferred from one node, no other nodes will be asked for state. This process is somewhat different from the initial state transfer process that occurs at startup when property FetchInMemoryState is set to true. During initial state transfer, only the oldest member of the cluster is queried for state. This approach is inadequate for region activation, as it is possible that the oldest member of the cluster also has the region inactivated, and thus cannot provide state. So, each node in the cluster is queried until one provides state.
Before requesting state from other nodes, activateRegion() will confirm that there is no existing data in the portion of the tree being activated. If there is any, a RegionNotEmptyException will be thrown.
It is important to understand that when a region of the tree is marked as inactive, this only means replication traffic from other cluster nodes related to that portion of the tree will be ignored. It is still technically possible for objects to be placed in the inactive portion of the tree locally (via a put call), and any such local activity will be replicated to other nodes. TreeCache will not prevent this kind of local activity on an inactive region, but, as discussed above activateRegion() will throw an exception if it discovers data in a region that is being activated.