Terracotta 10.7 | Ehcache API Developer Guide | Clustered Caches | Configuring a Clustered Cache
 
Configuring a Clustered Cache
Clustered Storage Tier
CacheConfiguration<Long, String> config =
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(2, MemoryUnit.MB) // <1>
.with(ClusteredResourcePoolBuilder.clusteredDedicated(
"primary-server-resource", 8, MemoryUnit.MB))) // <2>
.add(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
.build();

Cache<Long, String> cache = cacheManager.createCache("clustered-cache", config);
cache.put(42L, "All you need to know!");
1
Configuring the heap tier for cache.
2
Configuring the cluster tier of dedicated size from server off-heap resource using ClusteredResourcePoolBuilder.
The equivalent XML configuration is as follows:
<cache alias="clustered-cache">
<resources>
<heap unit="MB">10</heap> <!-- 1 -->
<tc:clustered-dedicated unit="MB">50</tc:clustered-dedicated> <!-- 2 -->
</resources>
<tc:clustered-store consistency="strong"/>
</cache>
1
Specify the heap tier for cache.
2
Specify the cluster tier for cache through a custom service configuration from the clustered namespace.
Specifying consistency level
Ehcache offers two levels of consistency:
Eventual
This consistency level indicates that the visibility of a write operation is not guaranteed when the operation returns. Other clients may still see a stale value for the given key. However this consistency level guarantees that for a mapping (K, V1) updated to (K, V2), once a client sees (K, V2) it will never see (K, V1) again.
Strong
This consistency level provides strong visibility guarantees ensuring that when a write operation returns other clients will be able to observe it immediately. This comes with a latency penalty on the write operation required to give this guarantee.
CacheConfiguration<Long, String> config =
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredDedicated(
"primary-server-resource", 2, MemoryUnit.MB)))
.add(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG)) // <1>
.build();

Cache<Long, String> cache = cacheManager.createCache("clustered-cache", config);
cache.put(42L, "All you need to know!"); // <2>
1
Specify the consistency level through the use of additional service configuration, using strong consistency here.
2
With the consistency used above, this put operation will return only when all other clients have had the corresponding mapping invalidated.
The equivalent XML configuration is as follows:
<cache alias="clustered-cache">
<resources>
<tc:clustered-dedicated unit="MB">50</tc:clustered-dedicated>
</resources>
<tc:clustered-store consistency="strong"/> <!-- 1 -->
</cache>
1
Specify the consistency level through a custom service configuration from the clustered namespace.
Clustered Cache Expiry
Expiry in clustered caches work with an exception that Expiry#getExpiryForAccess is handled on a best effort basis for cluster tiers. It may not be as accurate as in the case of local tiers.
Clustered Unspecified Inheritance
We have included an option which allows a cache to be created inside the cache manager without having to explicitly define its cluster tier resource pool allocation. In order to use this feature the cluster tier must already have been created with either a shared or dedicated resource pool.
In this case the definition of the cluster resource is done simply with a clustered() resource pool. This effectively means unspecified and indicates you expect it to exist already. It will then inherit the clustered resource pool as it was configured when creating the cluster tier.
This option provides many benefits. The main benefit is it simplifies clustered configuration by allowing clustered resource pool configuration to be handled by one client, then all subsequent clients can inherit this configuration. In addition, it also reduces clustered pool allocation configuration errors. More importantly, sizing calculations only need to be done by one person and updated in one location. Thus any programmer can use the cache without having to worry about using matching resource pool allocations.
The example code below shows how this can be implemented.
CacheManagerBuilder<PersistentCacheManager> cacheManagerBuilderAutoCreate =
CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(
URI.create("terracotta://localhost:9410/my-application"))
.autoCreate() // <1>
.resourcePool("resource-pool", 32, MemoryUnit.MB, "primary-server-resource"));

final PersistentCacheManager cacheManager1 = cacheManagerBuilderAutoCreate.build(false);
cacheManager1.init();

CacheConfiguration<Long, String> cacheConfigDedicated =
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredDedicated(
"primary-server-resource", 8, MemoryUnit.MB))) // <2>
.add(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
.build();

Cache<Long, String> cacheDedicated = cacheManager1.createCache(
"my-dedicated-cache", cacheConfigDedicated); // <3>

CacheManagerBuilder<PersistentCacheManager> cacheManagerBuilderExpecting =
CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(
URI.create("terracotta://localhost:9410/my-application"))
.expecting() // <4>
.resourcePool("resource-pool", 32, MemoryUnit.MB, "primary-server-resource"));

final PersistentCacheManager cacheManager2 = cacheManagerBuilderExpecting.build(false);
cacheManager2.init();

CacheConfiguration<Long, String> cacheConfigUnspecified =
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clustered())) // <5>
.add(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
.build();

Cache<Long, String> cacheUnspecified = cacheManager2.createCache(
"my-dedicated-cache", cacheConfigUnspecified); // <6>
1
Configure the first cache manager with auto create
2
Build a cache configuration for a clustered dedicated resource pool
3
Create cache my-dedicated-cache using the cache configuration
4
Configure the second cache manager as expecting (auto create off)
5
Build a cache configuration for a clustered unspecified resource pool, which will use the previously configured clustered dedicated resource pool.
6
Create cache with the same name my-dedicated-cache and use the clustered unspecified cache configuration