package com.hazelcast.examples.nearcache; import com.hazelcast.cache.ICache; import com.hazelcast.config.CacheConfig; import com.hazelcast.config.NearCacheConfig; import java.util.concurrent.TimeUnit; import static com.hazelcast.examples.helper.CommonUtils.sleepSeconds; import static com.hazelcast.spi.properties.GroupProperty.CACHE_INVALIDATION_MESSAGE_BATCH_FREQUENCY_SECONDS; import static java.lang.Integer.parseInt; /** * Code sample to demonstrate Near Cache behaviour when per entry invalidation is disabled. */ public class ClientNearCacheUsageWhenPerEntryInvalidationIsDisabled extends ClientNearCacheUsageSupport { private static final int RECORD_COUNT = 1000; private static final boolean VERBOSE = Boolean.getBoolean("com.hazelcast.examples.jcache.nearcache.verbose"); private static final int INVALIDATION_EVENT_FLUSH_FREQ_SECONDS = parseInt(CACHE_INVALIDATION_MESSAGE_BATCH_FREQUENCY_SECONDS.getDefaultValue()); public void run() { NearCacheConfig nearCacheConfig = createNearCacheConfig() .setInvalidateOnChange(true); CacheConfig<Integer, String> cacheConfig = createCacheConfig(); cacheConfig.setDisablePerEntryInvalidationEvents(true); ICache<Integer, String> clientCache1 = createCacheWithNearCache(cacheConfig, nearCacheConfig); ICache<Integer, String> clientCache2 = getCacheWithNearCache(nearCacheConfig); // put records to remote cache through client-1 putRecordsToCacheOnClient1(clientCache1); // get records from remote cache through client-2 getRecordsFromCacheOnClient2(clientCache2); // get records from Near Cache on client-2 getRecordsFromNearCacheOnClient2(clientCache2); // update records in remote cache through client-1 updateRecordsInCacheOnClient1(clientCache1); // wait a little for invalidation events to be sent in batch sleepSeconds(2 * INVALIDATION_EVENT_FLUSH_FREQ_SECONDS); // get old records from Near Cache on client-2 (because we have disabled per entry invalidation event) getStillOldRecordsFromNearCacheOnClient2(clientCache2); // clear cache through client-1 clientCache1.clear(); // wait a little for invalidation events to be sent in batch sleepSeconds(2 * INVALIDATION_EVENT_FLUSH_FREQ_SECONDS); // try to get records from Near Cache and can't find any, since they are invalidated from Near Cache on client-2 // due to clear() on client-1, because it's a full-flush operation and triggers invalidation even though // per entry invalidation event is disabled cantFindAnyRecordFromNearCacheOnClient2(clientCache2); shutdown(); } private void putRecordsToCacheOnClient1(ICache<Integer, String> clientCache1) { for (int i = 0; i < RECORD_COUNT; i++) { String value = generateValueFromKey(i); clientCache1.put(i, value); if (VERBOSE) { System.out.println("Put key=" + i + ", value=" + value + " to cache through client-1"); } } System.out.println(RECORD_COUNT + " records have been put to cache through client-1"); } private void getRecordsFromCacheOnClient2(ICache<Integer, String> clientCache2) { long started = System.nanoTime(); for (int i = 0; i < RECORD_COUNT; i++) { // these get() calls populate the Near Cache, so at the next calls, // the values will be taken from local Near Cache without any remote access String actualValue = clientCache2.get(i); String expectedValue = generateValueFromKey(i); assert actualValue.equals(expectedValue) : "Taken value from cache must be " + expectedValue + " but it is " + actualValue; if (VERBOSE) { System.out.println("Get key=" + i + ", value=" + actualValue + " from cache through client-2"); } } long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - started); System.out.println("Get records from cache finished in " + elapsed + " milliseconds"); } private void getRecordsFromNearCacheOnClient2(ICache<Integer, String> clientCache2) { long started = System.nanoTime(); for (int i = 0; i < RECORD_COUNT; i++) { // since this record has been put to Near Cache before, // it is taken from the local Near Cache without any remote access String actualValue = clientCache2.get(i); String expectedValue = generateValueFromKey(i); assert actualValue.equals(expectedValue) : "Taken value from Near Cache must be " + expectedValue + " but it is " + actualValue; if (VERBOSE) { System.out.println("Get key=" + i + ", value=" + actualValue + " from Near Cache on client-2"); } } long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - started); System.out.println("Get records from Near Cache finished in " + elapsed + " milliseconds"); } private void updateRecordsInCacheOnClient1(ICache<Integer, String> clientCache1) { for (int i = 0; i < RECORD_COUNT; i++) { String value = generateValueFromKey(RECORD_COUNT + i); clientCache1.put(i, value); if (VERBOSE) { System.out.println("Update key=" + i + ", value=" + value + " to cache through client-1"); } } System.out.println(RECORD_COUNT + " records have been updated in cache through client-1"); } private void getStillOldRecordsFromNearCacheOnClient2(ICache<Integer, String> clientCache2) { long started = System.nanoTime(); for (int i = 0; i < RECORD_COUNT; i++) { // these records have not been invalidated in the Near Cache on client-2, // because client-1 has updated the records and per entry invalidation event is disabled, // so invalidation events are not sent to client-2 (so this record has still its old value) String actualValue = clientCache2.get(i); String expectedValue = generateValueFromKey(i); assert actualValue.equals(expectedValue) : "Taken value from Near Cache must not be updated value " + actualValue + " but old value " + expectedValue + ". Because it must not be invalidated disabled per entry invalidation."; if (VERBOSE) { System.out.println("Get key=" + i + ", old value=" + actualValue + " from Near Cache through client-2 after update"); } } long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - started); System.out.println("Get old records from Near Cache after update finished in " + elapsed + " milliseconds"); } private void cantFindAnyRecordFromNearCacheOnClient2(ICache<Integer, String> clientCache2) { long started = System.nanoTime(); for (int i = 0; i < RECORD_COUNT; i++) { String value = clientCache2.get(i); assert value == null : "Taken value from Near Cache must not be there but it is " + value + ". Because it must be invalidated due to clear on cache!"; if (VERBOSE && value != null) { System.out.println("Get key=" + i + ", value=" + value + " from Near Cache through client-2 after clear()"); } } long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - started); System.out.println("Get records from Near Cache after clear() finished in " + elapsed + " milliseconds"); } public static void main(String[] args) { ClientNearCacheUsageWhenPerEntryInvalidationIsDisabled clientNearCacheUsage = new ClientNearCacheUsageWhenPerEntryInvalidationIsDisabled(); clientNearCacheUsage.run(); } }