Skip to content

Quick start

Vladimir Rodionov edited this page Dec 26, 2025 · 16 revisions

Table of contents

  1. Create In-Memory Cache
  2. Create Disk-Based Cache
  3. Create Hybrid Cache
  4. Create Tandem Cache
  5. Create cache using cache configuration file
  6. Load cache from a disk with a configuration file
  7. Load cache from a disk (programmatically)
  8. Usage example

Create In-Memory Cache

import com.carrotdata.cache.*;
import com.carrotdata.cache.controllers.*;
import com.carrotdata.cache.index.*;

protected Cache createInMemoryCache(String cacheName) throws IOException {
    // Data directory is needed even for in-memory cache; this is where 
    // data from memory can be saved to. This example uses temporary data folder just for
    // the API demonstration purposes, in a real application you will need to provide
    // some persistent folder path or use default one: "./data"

    Path dataDirPath = Files.createTempDirectory(null);
    String dataDir = dataDirPath.toFile().getAbsolutePath();
    
    Builder builder = new Builder(cacheName);
    
    builder
      .withCacheDataSegmentSize(16_777_216)  // 16MB
      .withCacheMaximumSize(8_589_934_592)  // 8GB 
      .withRecyclingSelector(MinAliveRecyclingSelector.class.getName())
      .withDataDir(dataDir)
      .withMainQueueIndexFormat(SubCompactBaseWithExpireIndexFormat.class.getName())  // This index format supports cache expiration 
      .withAdmissionController(ExpirationAwareAdmissionController.class.getName());  // This controller does some smart things :)
    return builder.buildMemoryCache();
}

Create Disk-Based Cache

import com.carrotdata.cache.*;
import com.carrotdata.cache.controllers.*;
import com.carrotdata.cache.index.*;

protected Cache createDiskCache(String cacheName) throws IOException {
    Path dataDirPath = Files.createTempDirectory(null);
    String dataDir = dataDirPath.toFile().getAbsolutePath();
    
    Builder builder = new Builder(cacheName);
    
    builder
      .withCacheDataSegmentSize(67_108_864)  // 64MB
      .withCacheMaximumSize(687_194_767_360)  // 640GB 
      .withRecyclingSelector(MinAliveRecyclingSelector.class.getName())  // Specify recycling selector type
      .withDataDir(dataDir)
      .withMainQueueIndexFormat(SubCompactBaseWithExpireIndexFormat.class.getName())  // This index format supports cache expiration 
      .withAdmissionController(ExpirationAwareAdmissionController.class.getName());  // Specify cache admission controller
    return builder.buildDiskCache();
}

Create Hybrid Cache (RAM -> SSD)

protected Cache createHybridCache(String ramCacheName, String diskCacheName) throws IOException {
    Cache ramCache = createInMemoryCache(ramCacheName);
    Cache diskCache = createDiskCache(diskCacheName);
    ramCache.setVictimCache(diskCache);
    return ramCache;
}

Create Tandem Cache (RAM -> Compressed RAM)

import com.carrotdata.cache.*;
import com.carrotdata.cache.controllers.*;
import com.carrotdata.cache.index.*;

protected Cache createInMemoryCompressedCache(String cacheName) throws IOException {
    // Data directory is needed even for in-memory cache; this is where 
    // data from memory can be saved to
    Path dataDirPath = Files.createTempDirectory(null);
    String dataDir = dataDirPath.toFile().getAbsolutePath();
    
    Builder builder = new Builder(cacheName);
    
    builder
      .withCacheDataSegmentSize(16_777_216)  // 16MB
      .withCacheMaximumSize(34_359_738_368)  // 32GB 
      .withCacheCompressionEnabled(true)  // Enable compression
      .withRecyclingSelector(MinAliveRecyclingSelector.class.getName())
      .withDataDir(dataDir)
      .withMainQueueIndexFormat(SubCompactBaseWithExpireIndexFormat.class.getName())  // This index format supports cache expiration 
      .withAdmissionController(ExpirationAwareAdmissionController.class.getName());  // This controller does some smart things :)
    return builder.buildMemoryCache();
}

protected Cache createTandemCache(String ramCacheName, String ramCompressedCacheName) throws IOException {
    Cache ramCache = createInMemoryCache(ramCacheName);
    Cache compCache = createInMemoryCompressedCache(ramCompressedCacheName);
    ramCache.setVictimCache(compCache);
    return ramCache;
}

Create cache using cache configuration file

The code below demonstrates a generic method for creating caches, including multi-level configurations, from a supplied configuration file. This approach allows you to easily define and manage cache settings, enabling flexible customization to suit various application requirements. By leveraging a configuration file, you can efficiently set up complex cache structures without hardcoding parameters, ensuring that your cache setup remains adaptable and scalable as your needs evolve.

import com.carrotdata.cache.*;

protected Cache createCacheFromConfigFile(String pathToFile) throws IOException {
  // Load configuration from a file
  CacheConfig conf = CacheConfig.getInstance(pathToFile);
  String[] cacheNames = conf.getCacheNames();
  Cache cache = null, mainCache = null;
  for (String name : cacheNames) {
    Cache c = new Cache(name);
    if (mainCache == null) {
      mainCache = c;
    }
    if (cache != null) {
      cache.setVictimCache(c);
    }
    cache = c;
  }
  return mainCache;
}

Load cache from a disk with a configuration file

The code below demonstrates a generic method for loading caches from a saved snapshot on disk. This approach ensures that your cache can be quickly restored to its previous state, minimizing downtime and eliminating the need to rebuild the cache from scratch. By leveraging saved snapshots, you can preserve important cached data across sessions, enhancing both the reliability and performance of your application.

import com.carrotdata.cache.*;

protected Cache loadCache(String pathToFile) throws IOException {
  // Load configuration from a file
  CacheConfig conf = CacheConfig.getInstance(pathToFile);
  String[] cacheNames = conf.getCacheNames();
  if (cacheNames == null || cacheNames.length == 0) {
    throw new IOException("No cache(s) were defined in the configuration file");
  }
  String mainCache = cacheNames[0];
  Cache c = null;
  if (conf.isSaveOnShutdown(mainCache)) {        
    for (int i = 0; i < cacheNames.length; i++) {
      Cache cc = Cache.loadCache(cacheNames[i]);
      if (cc == null) {
        LOG.error("Failed to load cache '{}', will initialize cache from configuration file instead.", cacheNames[i]);
        cache = null;
        // TODO: dispose?
        break;
      }
      if (c != null) {
        c.setVictimCache(cc);
      } else {
        cache = cc;
      }
      c = cc;
    }
  }

  if (cache == null) {
    // Nothing to load, so create new ones
    return createCacheFromConfigFile(pathToFile);
  }
}

Load cache from a disk (programmatically)

The code below demonstrates a generic method for loading caches from a saved snapshot on disk without relying on a configuration file, allowing the cache to be created purely programmatically. This approach is useful when flexibility and dynamic cache creation are required, as it enables you to restore the cache state directly in your code. By bypassing the need for a configuration file, you can tailor the cache initialization process to specific runtime conditions or application logic, ensuring a seamless and efficient recovery of cached data.

import com.carrotdata.cache.*;

protected Cache loadOrCreateMemoryCache(String cacheName) throws IOException {
  Cache cache = null;
  if (conf.isSaveOnShutdown(mainCache)) {        
      cache = Cache.loadCache(cacheName);
  }
  if (cache == null) {
    // Nothing to load, so create new ones
    return createInMemoryCache(cacheName);
  }
}

protected Cache loadOrCreateDiskCache(String cacheName) throws IOException {
  Cache cache = null;
  if (conf.isSaveOnShutdown(mainCache)) {        
      cache = Cache.loadCache(cacheNames[i]);
  }
  if (cache == null) {
    // Nothing to load, so create new ones
    return createDiskCache(cacheName);
  }
}

protected Cache createCache() throws IOException {
  String mainCacheName = "L1Cache";
  String diskCacheName = "L2Cache";
  Cache mainCache = loadOrCreateMemoryCache(mainCacheName);
  Cache diskCache  = loadOrCreateDiskCache(diskCacheName);
  mainCache.setVictimCache(diskCache);
  return mainCache;
}

Usage example

Cache cache = createInMemoryCache("ram1");
byte[] key1 = "key1".getBytes(StandardCharsets.UTF_8);
byte[] value1 = "value1".getBytes(StandardCharsets.UTF_8);

// Put key-value without expiration time
cache.put(key1, value1, 0);

byte[] key2 = "key2".getBytes(StandardCharsets.UTF_8);
byte[] value2 = "value2".getBytes(StandardCharsets.UTF_8);

// Put key-value with expiration time of 1 minute
cache.put(key2, value2, System.currentTimeMillis() + 60 * 1000);
byte[] buffer = new byte[value2.length];
int size = cache.get(key2, 0, key2.length, buffer, 0);
String result = new String(buffer, 0, size, StandardCharsets.UTF_8);
System.out.printf("Value for key %s is %s", key2, result);

Note: Carrot Cache, by default, disables both: compression and expiration support. You have to enable them either through configuration file if you use it to create a cache or programmatically.

  • Config file
cache.names=L1
cache.types=memory

# Enable compression for cache 'L1'
L1.compression.enabled=true
# Set index format which supports object's expiration
L1.index.format.impl=com.carrotdata.cache.index.SubCompactBaseNoSizeWithExpireIndexFormat
# Set recycling selector to MinAlive
L1.recycling.selector.impl=com.carrotdata.cache.controllers.MinAliveRecyclingSelector
# Set optimized admission controller
L1.admission.controller.impl=com.carrotcache.cache.controllers.ExpirationAwareAdmissionController
  • Java API
import com.carrotdata.cache.*;
import com.carrotcache.cache.controllers.*;
import com.carrotdata.cache.index.*;

protected createCache(String cacheName) {
  Builder b =  new Builder(cacheName);
   b.withCacheCompressionEnabled(true).
   b.withRecyclingSelector(MinAliveRecyclingSelector.class.getName())  // Specify recycling selector type
   b.withMainQueueIndexFormat(SubCompactBaseNoSizeWithExpireIndexFormat.class.getName())  // This index format supports cache expiration 
   b.withAdmissionController(ExpirationAwareAdmissionController.class.getName());  // Specify cache admission controller
   // ...
   return b.buildMemoryCache();
}