com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links' is unknown.

Multi-tenant Caching based on Hazelcast

Further to the WSO2 Carbon 4.2.0 kernel release, we have moved from Tribes to Hazelcast, and have also introduced a new JSR-107 (JCache) caching implementation.

Core features

  1. Local and distributed mode
  2. L1 and L2 caching model for distributed mode
  3. Multi-tenancy
This cache supports both local mode and distributed mode. If (Axis2) clustering is enabled, the cache works as a distributed cache. It is simply using a Hazelcast distributed map per cache. If clustering is not enabled, then the same caching implementation works as a local cache. There is no code change required in the code that uses JCache APIs to switch from local cache mode to distributed cache mode.

In addition, in the distributed cache mode, in order to improve performance, a L1 and L2 cache is present. The L1 cache is implemented using HashMaps, and the L2 cache is implemented using Hazelcast distributed maps. As a result, first the L1 cache is checked, and if there is a cache miss, then the L2 cache is checked. If the value is located in the L2 cache, then the value is also stored it in the L1 cache. This is illustrated in the sequence diagram below:



In the distributed mode, if a cache entry is removed, invalidated or changed, then the Hazelcast listeners that have been registered get triggered on each and every Hazelcast cluster member. That will result in the values in the L1 cache and the L2 cache being removed or updated. The following sequence diagram depicts this:



Each cache operation is automatically tenant qualified. The tenant is derived from the thread context using the CarbonContext tenant ID and tenant domain. Caches created by a particular tenant can only be accessed by that tenant. This ensures that tenants cannot gain illegal access to caches owned by other tenants.

Code examples

The following examples illustrate how the JCache APIs can be used to acquire the cache and carryout caching operations.

Example 1: Simple cache creation

CacheManager cacheManager = Caching.getCacheManagerFactory().getCacheManager("sampleCacheManager");
Cache<String, Integer> cache = cacheManager.getCache("sampleCache");
String key = "1";
int value1 = 9876;
cache.put(key, value1);
int value = cache.get(key).intValue();

Example 2: Using cache configuration with a custom cache expiry

CacheManager cacheManager = Caching.getCacheManagerFactory().getCacheManager("test");
        String cacheName = "cacheXXX";
        cache = cacheManager.<String,Integer>createCacheBuilder(cacheName).setExpiry(CacheConfiguration.ExpiryType.MODIFIED, new 	   CacheConfiguration.Duration(TimeUnit.SECONDS, 10)). 
                setStoreByValue(false).build();
        int value = 9876;  
        cache.put(key, value); 
        assertEquals(cache.get(key).intValue(), value); 
The relevant code is available at the following SVN locations;The relevant code is available at the following SVN locations;

The relevant code is available at the following SVN locations:

com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links2' is unknown.