Chapter 7. The Persistence SPI
7.1. The Persistence SPI
In Red Hat JBoss Data Grid, persistence can configure external (persistent) storage engines. These storage engines complement Red Hat JBoss Data Grid’s default in-memory storage.
Persistent external storage provides several benefits:
- Memory is volatile and a cache store can increase the life span of the information in the cache, which results in improved durability.
- Using persistent external stores as a caching layer between an application and a custom storage engine provides improved Write-Through functionality.
- Using a combination of eviction and passivation, only the frequently required information is stored in-memory and other data is stored in the external storage.
Programmatically configuring persistence can only be accomplished in Red Hat JBoss Data Grid’s Library Mode.
7.2. Persistence SPI Benefits
The Red Hat JBoss Data Grid implementation of the Persistence SPI offers the following benefits:
-
Alignment with JSR-107 (http://jcp.org/en/jsr/detail?id=107). JBoss Data Grid’s
CacheWriter
andCacheLoader
interfaces are similar to the JSR-107 writer and reader. As a result, alignment with JSR-107 provides improved portability for stores across JCache-compliant vendors. - Simplified transaction integration. JBoss Data Grid handles locking automatically and so implementations do not have to coordinate concurrent access to the store. Depending on the locking mode, concurrent writes on the same key may not occur. However, implementors expect operations on the store to originate from multiple threads and add the implementation code accordingly.
- Reduced serialization, resulting in reduced CPU usage. The new SPI exposes stored entries in a serialized format. If an entry is fetched from persistent storage to be sent remotely, it does not need to be deserialized (when reading from the store) and then serialized again (when writing to the wire). Instead, the entry is written to the wire in the serialized format as fetched from the storage.
7.3. Programmatically Configure the Persistence SPI
The following is a sample programmatic configuration for a Single File Store using the Persistence SPI:
Configure the Single File Store via the Persistence SPI
ConfigurationBuilder builder = new ConfigurationBuilder(); builder.persistence() .passivation(false) .addSingleFileStore() .preload(true) .shared(false) .fetchPersistentState(true) .ignoreModifications(false) .purgeOnStartup(false) .location(System.getProperty("java.io.tmpdir")) .async() .enabled(true) .threadPoolSize(5) .singleton() .enabled(true) .pushStateWhenCoordinator(true) .pushStateTimeout(20000);
7.4. Persistence Examples
7.4.1. Persistence Examples
The following examples demonstrate how to configure various cache stores implementations programmatically. For a comparison of these stores, along with additional information on each, refer to the Administration and Configuration Guide.
7.4.2. Configure the Cache Store Programmatically
The following example demonstrates how to configure the cache store programmatically:
ConfigurationBuilder builder = new ConfigurationBuilder(); builder.persistence() .passivation(false) .addSingleFileStore() .shared(false) .preload(true) .fetchPersistentState(true) .purgeOnStartup(false) .location(System.getProperty("java.io.tmpdir")) .async() .enabled(true) .threadPoolSize(5) .singleton() .enabled(true) .pushStateWhenCoordinator(true) .pushStateTimeout(20000);
This configuration is for a single-file cache store. Some attributes, such as location
are specific to the single-file cache store and are not used for other types of cache stores.
Configure the Cache store Programatically
-
Use the
ConfigurationBuilder
to create a new configuration object. -
The
passivation
elements affects the way Red Hat JBoss Data Grid interacts with stores. Passivation removes an object from an in-memory cache and writes it to a secondary data store, such as a system or database. If no secondary data store exists, then the object will only be removed from the in-memory cache. Passivation isfalse
by default. -
The
addSingleFileStore()
elements adds the SingleFileStore as the cache store for this configuration. It is possible to create other stores, such as a JDBC Cache Store, which can be added using theaddStore
method. -
The
shared
parameter indicates that the cache store is shared by different cache instances. For example, where all instances in a cluster use the same JDBC settings to talk to the same remote, shared database.shared
isfalse
by default. When set totrue
, it prevents duplicate data being written to the cache store by different cache instances. -
The
preload
element is set tofalse
by default. When set totrue
the data stored in the cache store is preloaded into the memory when the cache starts. This allows data in the cache store to be available immediately after startup and avoids cache operations delays as a result of loading data lazily. Preloaded data is only stored locally on the node, and there is no replication or distribution of the preloaded data. JBoss Data Grid will only preload up to the maximum configured number of entries in eviction. -
The
fetchPersistentState
element determines whether or not to fetch the persistent state of a cache and apply it to the local cache store when joining the cluster. If the cache store is shared the fetch persistent state is ignored, as caches access the same cache store. A configuration exception will be thrown when starting the cache service if more than one cache store has this property set totrue
. ThefetchPersistentState
property isfalse
by default. -
The
purgeOnStartup
element controls whether cache store is purged when it starts up and isfalse
by default. -
The
location
element configuration element sets a location on disk where the store can write. -
These attributes configure aspects specific to each cache store. For example, the
location
attribute points to where the SingleFileStore will keep files containing data. Other stores may require more complex configuration. -
The
singleton
element enables modifications to be stored by only one node in the cluster. This node is called the coordinator. The coordinator pushes the caches in-memory states to disk. This function is activated by setting theenabled
attribute totrue
in all nodes. Theshared
parameter cannot be defined withsingleton
enabled at the same time. Theenabled
attribute isfalse
by default. -
The
pushStateWhenCoordinator
element is set totrue
by default. Iftrue
, this property will cause a node that has become the coordinator to transfer in-memory state to the underlying cache store. This parameter is useful where the coordinator has crashed and a new coordinator is elected.
7.4.3. LevelDB Cache Store Programmatic Configuration
The following is a sample programmatic configuration of LevelDB Cache Store:
Configuration cacheConfig = new ConfigurationBuilder().persistence() .addStore(LevelDBStoreConfigurationBuilder.class) .location("/tmp/leveldb/data") .expiredLocation("/tmp/leveldb/expired").build();
LevelDB Cache Store programmatic configuration
-
Use the
ConfigurationBuilder
to create a new configuration object. -
Add the store using
LevelDBCacheStoreConfigurationBuilder
class to build its configuration. - Set the LevelDB Cache Store location path. The specified path stores the primary cache store data. The directory is automatically created if it does not exist.
-
Specify the location for expired data using the
expiredLocation
parameter for the LevelDB Store. The specified path stores expired data before it is purged. The directory is automatically created if it does not exist.
7.4.4. JdbcBinaryStore Programmatic Configuration
The JdbcBinaryStore
supports all key types by storeing all keys with the same hash value (hashCode
method on the key) in the same table row/blob.
Binary JDBC stores are deprecated in JBoss Data Grid 7.2, and are not recommended for production use. It is recommended to utilize a String Based store instead.
The following is a sample configuration for the JdbcBinaryStore :
ConfigurationBuilder builder = new ConfigurationBuilder(); builder.persistence() .addStore(JdbcBinaryStoreConfigurationBuilder.class) .fetchPersistentState(false) .ignoreModifications(false) .purgeOnStartup(false) .table() .dropOnExit(true) .createOnStart(true) .tableNamePrefix("ISPN_BUCKET_TABLE") .idColumnName("ID_COLUMN").idColumnType("VARCHAR(255)") .dataColumnName("DATA_COLUMN").dataColumnType("BINARY") .timestampColumnName("TIMESTAMP_COLUMN").timestampColumnType("BIGINT") .connectionPool() .connectionUrl("jdbc:h2:mem:infinispan_binary_based;DB_CLOSE_DELAY=-1") .username("sa") .driverClass("org.h2.Driver");
JdbcBinaryStore Programmatic Configuration (Library Mode)
-
Use the
ConfigurationBuilder
to create a new configuration object. -
Add the
JdbcBinaryStore
configuration builder to build a specific configuration related to this store. -
The
fetchPersistentState
element determines whether or not to fetch the persistent state of a cache and apply it to the local cache store when joining the cluster. If the cache store is shared the fetch persistent state is ignored, as caches access the same cache store. A configuration exception will be thrown when starting the cache service if more than one cache loader has this property set totrue
. ThefetchPersistentState
property isfalse
by default. -
The
ignoreModifications
element determines whether write methods are pushed to the specific cache loader by allowing write operations to the local file cache loader, but not the shared cache loader. In some cases, transient application data should only reside in a file-based cache loader on the same server as the in-memory cache. For example, this would apply with a further JDBC based cache loader used by all servers in the network.ignoreModifications
isfalse
by default. -
The
purgeOnStartup
element specifies whether the cache is purged when initially started. Configure the table as follows:
-
dropOnExit
determines if the table will be dropped when the cache store is stopped. This is set tofalse
by default. -
createOnStart
creates the table when starting the cache store if no table currently exists. This method istrue
by default. -
tableNamePrefix
sets the prefix for the name of the table in which the data will be stored. -
The
idColumnName
property defines the column where the cache key or bucket ID is stored. -
The
dataColumnName
property specifies the column where the cache entry or bucket is stored. -
The
timestampColumnName
element specifies the column where the time stamp of the cache entry or bucket is stored.
-
The
connectionPool
element specifies a connection pool for the JDBC driver using the following parameters:-
The
connectionUrl
parameter specifies the JDBC driver-specific connection URL. -
The
username
parameter contains the user name used to connect via theconnectionUrl
. -
The
driverClass
parameter specifies the class name of the driver used to connect to the database.
-
The
7.4.5. JdbcStringBasedStore Programmatic Configuration
The JdbcStringBasedStore
stores each entry in its own row in the table, instead of grouping multiple entries into each row, resulting in increased throughput under a concurrent load.
The following is a sample configuration for the JdbcStringBasedStore :
ConfigurationBuilder builder = new ConfigurationBuilder(); builder.persistence().addStore(JdbcStringBasedStoreConfigurationBuilder.class) .fetchPersistentState(false) .ignoreModifications(false) .purgeOnStartup(false) .table() .dropOnExit(true) .createOnStart(true) .tableNamePrefix("ISPN_STRING_TABLE") .idColumnName("ID_COLUMN").idColumnType("VARCHAR(255)") .dataColumnName("DATA_COLUMN").dataColumnType("BINARY") .timestampColumnName("TIMESTAMP_COLUMN").timestampColumnType("BIGINT") .dataSource() .jndiUrl("java:jboss/datasources/JdbcDS");
Configure the JdbcStringBasedStore Programmatically
-
Use the
ConfigurationBuilder
to create a new configuration object. -
Add the
JdbcStringBasedStore
configuration builder to build a specific configuration related to this store. -
The
fetchPersistentState
parameter determines whether or not to fetch the persistent state of a cache and apply it to the local cache store when joining the cluster. If the cache store is shared the fetch persistent state is ignored, as caches access the same cache store. A configuration exception will be thrown when starting the cache service if more than one cache loader has this property set totrue
. ThefetchPersistentState
property isfalse
by default. -
The
ignoreModifications
parameter determines whether write methods are pushed to the specific cache loader by allowing write operations to the local file cache loader, but not the shared cache loader. In some cases, transient application data should only reside in a file-based cache loader on the same server as the in-memory cache. For example, this would apply with a further JDBC based cache loader used by all servers in the network.ignoreModifications
isfalse
by default. -
The
purgeOnStartup
parameter specifies whether the cache is purged when initially started. Configure the Table
-
dropOnExit
determines if the table will be dropped when the cache store is stopped. This is set tofalse
by default. -
createOnStart
creates the table when starting the cache store if no table currently exists. This method istrue
by default. -
tableNamePrefix
sets the prefix for the name of the table in which the data will be stored. -
The
idColumnName
property defines the column where the cache key or bucket ID is stored. -
The
dataColumnName
property specifies the column where the cache entry or bucket is stored. -
The
timestampColumnName
element specifies the column where the time stamp of the cache entry or bucket is stored.
-
The
dataSource
element specifies a data source using the following parameters:-
The
jndiUrl
specifies the JNDI URL to the existing JDBC.
-
The
An IOException Unsupported protocol version 48 error when using JdbcStringBasedStore
indicates that your data column type is set to VARCHAR
, CLOB
or something similar instead of the correct type, BLOB
or VARBINARY
. Despite its name, JdbcStringBasedStore
only requires that the keys are strings while the values can be any data type, so that they can be stored in a binary column.
7.4.6. JdbcMixedStore Programmatic Configuration
The JdbcMixedStore
is a hybrid implementation that delegates keys based on their type to either the JdbcBinaryStore
or JdbcStringBasedStore
.
Mixed JDBC stores are deprecated in JBoss Data Grid 7.2, and are not recommended for production use. It is recommended to utilize a String Based store instead.
The following is a sample configuration for the JdbcMixedStore :
ConfigurationBuilder builder = new ConfigurationBuilder(); builder.persistence().addStore(JdbcMixedStoreConfigurationBuilder.class) .fetchPersistentState(false) .ignoreModifications(false) .purgeOnStartup(false) .stringTable() .dropOnExit(true) .createOnStart(true) .tableNamePrefix("ISPN_MIXED_STR_TABLE") .idColumnName("ID_COLUMN").idColumnType("VARCHAR(255)") .dataColumnName("DATA_COLUMN").dataColumnType("BINARY") .timestampColumnName("TIMESTAMP_COLUMN").timestampColumnType("BIGINT") .binaryTable() .dropOnExit(true) .createOnStart(true) .tableNamePrefix("ISPN_MIXED_BINARY_TABLE") .idColumnName("ID_COLUMN").idColumnType("VARCHAR(255)") .dataColumnName("DATA_COLUMN").dataColumnType("BINARY") .timestampColumnName("TIMESTAMP_COLUMN").timestampColumnType("BIGINT") .connectionPool() .connectionUrl("jdbc:h2:mem:infinispan_binary_based;DB_CLOSE_DELAY=-1") .username("sa") .driverClass("org.h2.Driver");
Configure JdbcMixedStore Programmatically
-
Use the
ConfigurationBuilder
to create a new configuration object. -
Add the
JdbcMixedStore
configuration builder to build a specific configuration related to this store. -
The
fetchPersistentState
parameter determines whether or not to fetch the persistent state of a cache and apply it to the local cache store when joining the cluster. If the cache store is shared the fetch persistent state is ignored, as caches access the same cache store. A configuration exception will be thrown when starting the cache service if more than one cache loader has this property set totrue
. ThefetchPersistentState
property isfalse
by default. -
The
ignoreModifications
parameter determines whether write methods are pushed to the specific cache loader by allowing write operations to the local file cache loader, but not the shared cache loader. In some cases, transient application data should only reside in a file-based cache loader on the same server as the in-memory cache. For example, this would apply with a further JDBC based cache loader used by all servers in the network.ignoreModifications
isfalse
by default. -
The
purgeOnStartup
parameter specifies whether the cache is purged when initially started. Configure the table as follows:
-
dropOnExit
determines if the table will be dropped when the cache store is stopped. This is set tofalse
by default. -
createOnStart
creates the table when starting the cache store if no table currently exists. This method istrue
by default. -
tableNamePrefix
sets the prefix for the name of the table in which the data will be stored. -
The
idColumnName
property defines the column where the cache key or bucket ID is stored. -
The
dataColumnName
property specifies the column where the cache entry or bucket is stored. -
The
timestampColumnName
element specifies the column where the time stamp of the cache entry or bucket is stored.
-
The
connectionPool
element specifies a connection pool for the JDBC driver using the following parameters:-
The
connectionUrl
parameter specifies the JDBC driver-specific connection URL. -
The
username
parameter contains the username used to connect via theconnectionUrl
. -
The
driverClass
parameter specifies the class name of the driver used to connect to the database.
-
The
7.4.7. JPA Cache Store Sample Programmatic Configuration
To configure JPA Cache Stores programatically in Red Hat JBoss Data Grid, use the following:
Configuration cacheConfig = new ConfigurationBuilder().persistence() .addStore(JpaStoreConfigurationBuilder.class) .persistenceUnitName("org.infinispan.loaders.jpa.configurationTest") .entityClass(User.class) .build();
The parameters used in this code sample are as follows:
-
The
persistenceUnitName
parameter specifies the name of the JPA cache store in the configuration file (persistence.xml ) that contains the JPA entity class. -
The
entityClass
parameter specifies the JPA entity class that is stored in this cache. Only one class can be specified for each configuration.
7.4.8. Cassandra Cache Store Sample Programmatic Configuration
The Cassandra cache store is not part of the Red Hat JBoss Data Grid’s core libraries, and must be added to the classpath. For Maven projects this may be added with the following addition to your pom.xml
:
<dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-cachestore-cassandra</artifactId> <version>...</version> <!-- 7.2.0 or later --> </dependency>
The following configuration snippet provides an example on how to define a Cassandra Cache Store programmatically:
Configuration cacheConfig = new ConfigurationBuilder() .persistence() .addStore(CassandraStoreConfigurationBuilder.class) .addServer() .host("127.0.0.1") .port(9042) .addServer() .host("127.0.0.1") .port(9041) .autoCreateKeyspace(true) .keyspace("TestKeyspace") .entryTable("TestEntryTable") .consistencyLevel(ConsistencyLevel.LOCAL_ONE) .serialConsistencyLevel(ConsistencyLevel.SERIAL) .connectionPool() .heartbeatIntervalSeconds(30) .idleTimeoutSeconds(120) .poolTimeoutMillis(5) .build();