JBoss.orgCommunity Documentation

Chapter 9. Immutant Caching

9.1. Introduction

Immutant provides built-in support for local and distributed caches that implement core.cache/CacheProtocol, and may therefore be used as standard memoization stores. It is also possible to use them as enhanced ConcurrentMap implementations.

9.1.1. Infinispan

Immutant encapsulates the JBoss Infinispan data grid, enabling simple construction of transactional, high-performance key/value stores that can be either run locally or efficiently replicated across a cluster.

Infinispan offers a number of clustering modes that determine what happens when an entry is written to the cache.

9.2. Caching Modes

Infinispan supports three clustered modes and one non-clustered.

9.2.1. Local

This is the default mode when Immutant runs non-clustered, essentially an enhanced, in-memory ConcurrentMap implementation, featuring write-through/write-behind persistence, eviction, expiration, JTA/XA support, MVCC-based concurency, and JMX manageability.

9.2.2. Invalidated

This is the default mode when Immutant runs clustered. No data is actually shared among the cluster nodes in this mode. Instead, notifications are sent to all nodes when data changes, causing them to evict their stale copies of the updated entry.

9.2.3. Replicated

In this mode, entries added to any cache instance will be copied to all other cache instances in the cluster, and can then be retrieved locally from any instance. This mode is probably impractical for clusters of any significant size. Infinispan recommends 10 as a reasonable upper bound on the number of replicated nodes.

9.2.4. Distributed

This mode enables Infinispan clusters to achieve "linear scalability". Cache entries are copied to a fixed number of cluster nodes (2, by default) regardless of the cluster size. Distribution uses a consistent hashing algorithm to determine which nodes will store a given entry.

9.3. The API

Caches are defined using the immutant.cache/cache function. Its only required argument is a name.

Additionally, one of the following keywords may be passed to indicate the desired caching mode: :local, :invalidated, :replicated, or :distributed. If omitted, the default mode is :invalidated when clustered. When not clustered, the mode will always be :local, as the others are meaningless unless clustered.

The cache can also be seeded from a passed map as well.

Some examples are in order.

(ns example.test
  (:use [immutant.cache]))

;; Obtain a cache in :invalidated mode if clustered, :local otherwise
(def c1 (cache "jimi"))

;; A cache in :distributed mode if clustered, :local otherwise
(def c2 (cache "jeff" :distributed))

;; Initialize a cache with a seed
(def c3 (cache "billy" :replicated {:a 1 :b 2}))

;; If seed is second parameter, mode defaults to :invalidated/:local
(def c4 (cache "jerry" {:a 1 :b 2}))

In addition to providing implementations for many of Clojure's core interfaces, the returned cache object implements two useful protocols: core.cache/CacheProtocol and immutant.cache/Mutable. The former allows an Immutant cache to be plugged into the core.memoize API. The latter exposes some of Infinispan's handy cache manipulation features.

(defprotocol Mutable
  "Functions for manipulating a shared, distributed cache.

   Every function optionally accepts a map with the following
   lifespan-oriented keys:

     :ttl - time-to-live, the max time the entry will live before expiry [-1]
     :idle - the time after which an entry will expire if not accessed [-1]
     :units - the units for the values of :ttl and :idle [:seconds]

   Negative values imply no expiration.
   Possible values for :units -- :days, :hours, :minutes, :seconds,
                                 :milliseconds, :microseconds :nanoseconds

   The conditional functions, e.g. put-if-*, are all atomic."
  (put [cache key value] [cache key value options]
    "Put an entry in the cache")
  (put-all [cache map] [cache map options]
    "Put all the entries in cache")
  (put-if-absent [cache key value] [cache key value options]
    "Put it in only if key is not already there")
  (put-if-present [cache key value] [cache key value options]
    "Put it in only if key is already there")
  (put-if-replace [cache key old new] [cache key old new options]
    "Put it in only if key is there and current matches old")
  (delete [cache key] [cache key value]
    "Delete the entry; value must match current if passed"))
Immutant 0.1.0