Feature - Hibernate cache implementation #1732
parent
6e5bf64d09
commit
46aa0395c3
@ -0,0 +1,116 @@
|
||||
Redis based Hibernate Cache implementation
|
||||
===
|
||||
|
||||
Implements Hibernate 2nd level Cache provider based on Redisson.
|
||||
|
||||
Supports Hibernate 4.x, 5.x
|
||||
|
||||
<sub>Please consider __[Redisson PRO](https://redisson.pro)__ version for advanced features and support by SLA.</sub>
|
||||
|
||||
Usage
|
||||
===
|
||||
|
||||
### 1. Add `redisson-hibernate` dependency into your project:
|
||||
|
||||
1. __For JDK 1.8+__
|
||||
|
||||
Maven
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<!-- for Hibernate v4.x -->
|
||||
<artifactId>redisson-hibernate-4</artifactId>
|
||||
<!-- for Hibernate v5.0.x - v5.1.x -->
|
||||
<artifactId>redisson-hibernate-5</artifactId>
|
||||
<!-- for Hibernate v5.2.x -->
|
||||
<artifactId>redisson-hibernate-52</artifactId>
|
||||
<!-- for Hibernate v5.3.x -->
|
||||
<artifactId>redisson-hibernate-53</artifactId>
|
||||
<version>3.10.0</version>
|
||||
</dependency>
|
||||
```
|
||||
Gradle
|
||||
|
||||
```java
|
||||
// for Hibernate v4.x
|
||||
compile 'org.redisson:redisson-hibernate-4:3.10.0'
|
||||
// for Hibernate v5.0.x - v5.1.x
|
||||
compile 'org.redisson:redisson-hibernate-5:3.10.0'
|
||||
// for Hibernate v5.2.x
|
||||
compile 'org.redisson:redisson-hibernate-52:3.10.0'
|
||||
// for Hibernate v5.3.x
|
||||
compile 'org.redisson:redisson-hibernate-53:3.10.0'
|
||||
```
|
||||
|
||||
2. __For JDK 1.6+__
|
||||
|
||||
Maven
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<!-- for Hibernate v4.x -->
|
||||
<artifactId>redisson-hibernate-4</artifactId>
|
||||
<!-- for Hibernate v5.0.x - v5.1.x -->
|
||||
<artifactId>redisson-hibernate-5</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
```
|
||||
Gradle
|
||||
|
||||
```java
|
||||
// for Hibernate v4.x
|
||||
compile 'org.redisson:redisson-hibernate-4:2.15.0'
|
||||
// for Hibernate v5.0.x - v5.1.x
|
||||
compile 'org.redisson:redisson-hibernate-5:2.15.0'
|
||||
```
|
||||
|
||||
|
||||
### 2. Specify hibernate cache settings
|
||||
|
||||
```
|
||||
<!-- 2nd level cache activation -->
|
||||
<property name="hibernate.cache.use_second_level_cache" value="true" />
|
||||
<property name="hibernate.cache.use_query_cache" value="true" />
|
||||
|
||||
<!-- Redisson Hibernate Cache factory -->
|
||||
<property name="hibernate.cache.region.factory_class" value="org.redisson.hibernate.RedissonRegionFactory" />
|
||||
<!-- Redisson YAML config (searched in filesystem and classpath) -->
|
||||
<property name="hibernate.cache.redisson.config" value="/redisson.yaml" />
|
||||
<!-- Redisson JSON config (searched in filesystem and classpath) -->
|
||||
<property name="hibernate.cache.redisson.config" value="/redisson.json" />
|
||||
```
|
||||
|
||||
Redisson allows to define follow cache settings per entity, collection, naturalid, query and timestamp regions:
|
||||
`eviction.max_entries` - max size of cache. Superfluous entries are evicted using LRU algorithm. `0` value means unbounded cache. Default value: 0
|
||||
`expiration.time_to_live` - time to live per cache entry in milliseconds. `0` value means this setting doesn't affect expiration. Default value: 0
|
||||
`expiration.max_idle_time` - max idle time per cache entry in milliseconds. `0` value means this setting doesn't affect expiration. Default value: 0
|
||||
|
||||
Configuration examples:
|
||||
|
||||
```
|
||||
<!-- cache definition for entity region. Example region name: "my_object" -->
|
||||
<property name="hibernate.cache.redisson.my_object.eviction.max_entries" value="10000" />
|
||||
<property name="hibernate.cache.redisson.my_object.expiration.time_to_live" value="600000" />
|
||||
<property name="hibernate.cache.redisson.my_object.expiration.max_idle_time" value="300000" />
|
||||
|
||||
<!-- cache definition for collection region. Example region name: "my_list" -->
|
||||
<property name="hibernate.cache.redisson.my_list.eviction.max_entries" value="10000" />
|
||||
<property name="hibernate.cache.redisson.my_list.expiration.time_to_live" value="600000" />
|
||||
<property name="hibernate.cache.redisson.my_list.expiration.max_idle_time" value="300000" />
|
||||
|
||||
<!-- cache definition for naturalid region. Prefixed by ##NaturalId. Example region name: "my_object" -->
|
||||
<property name="hibernate.cache.redisson.my_object##NaturalId.eviction.max_entries" value="10000" />
|
||||
<property name="hibernate.cache.redisson.my_object##NaturalId.expiration.time_to_live" value="600000" />
|
||||
<property name="hibernate.cache.redisson.my_object##NaturalId.expiration.max_idle_time" value="300000" />
|
||||
|
||||
<!-- cache definition for query region. Example region name: "my_query" -->
|
||||
<property name="hibernate.cache.redisson.my_entity.eviction.max_entries" value="10000" />
|
||||
<property name="hibernate.cache.redisson.my_entity.expiration.time_to_live" value="600000" />
|
||||
<property name="hibernate.cache.redisson.my_entity.expiration.max_idle_time" value="300000" />
|
||||
|
||||
<!-- cache definition for timestamps region. -->
|
||||
<property name="hibernate.cache.redisson.timestamps.eviction.max_entries" value="10000" />
|
||||
<property name="hibernate.cache.redisson.timestamps.expiration.time_to_live" value="600000" />
|
||||
<property name="hibernate.cache.redisson.timestamps.expiration.max_idle_time" value="300000" />
|
||||
|
||||
```
|
@ -0,0 +1,64 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-parent</artifactId>
|
||||
<version>2.14.2-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>redisson-hibernate</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Redisson/Hibernate</name>
|
||||
|
||||
<modules>
|
||||
<module>redisson-hibernate-4</module>
|
||||
<module>redisson-hibernate-5</module>
|
||||
<module>redisson-hibernate-52</module>
|
||||
<module>redisson-hibernate-53</module>
|
||||
</modules>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.11.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.192</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,79 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-hibernate</artifactId>
|
||||
<version>2.14.2-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>redisson-hibernate-4</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Redisson/Hibernate-4.x</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>de.ruedigermoeller</groupId>
|
||||
<artifactId>fst</artifactId>
|
||||
<version>2.54</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>4.3.11.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-testing</artifactId>
|
||||
<version>4.3.11.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<basedir>${basedir}</basedir>
|
||||
<header>${basedir}/../../header.txt</header>
|
||||
<quiet>false</quiet>
|
||||
<failIfMissing>true</failIfMissing>
|
||||
<aggregate>false</aggregate>
|
||||
<includes>
|
||||
<include>src/main/java/org/redisson/</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>target/**</exclude>
|
||||
</excludes>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<mapping>
|
||||
<java>JAVADOC_STYLE</java>
|
||||
</mapping>
|
||||
<strictCheck>true</strictCheck>
|
||||
<useDefaultMapping>true</useDefaultMapping>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,227 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.QueryResultsRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TimestampsRegion;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RScript;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.client.codec.LongCodec;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.hibernate.region.RedissonCollectionRegion;
|
||||
import org.redisson.hibernate.region.RedissonEntityRegion;
|
||||
import org.redisson.hibernate.region.RedissonNaturalIdRegion;
|
||||
import org.redisson.hibernate.region.RedissonQueryRegion;
|
||||
import org.redisson.hibernate.region.RedissonTimestampsRegion;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonRegionFactory implements RegionFactory {
|
||||
|
||||
private static final Logger log = Logger.getLogger( RedissonRegionFactory.class );
|
||||
|
||||
private static final long serialVersionUID = 3785315696581773811L;
|
||||
|
||||
public static final String QUERY_DEF = "query";
|
||||
|
||||
public static final String COLLECTION_DEF = "collection";
|
||||
|
||||
public static final String ENTITY_DEF = "entity";
|
||||
|
||||
public static final String NATURAL_ID_DEF = "naturalid";
|
||||
|
||||
public static final String TIMESTAMPS_DEF = "timestamps";
|
||||
|
||||
public static final String MAX_ENTRIES_SUFFIX = ".eviction.max_entries";
|
||||
|
||||
public static final String TTL_SUFFIX = ".expiration.time_to_live";
|
||||
|
||||
public static final String MAX_IDLE_SUFFIX = ".expiration.max_idle_time";
|
||||
|
||||
public static final String CONFIG_PREFIX = "hibernate.cache.redisson.";
|
||||
|
||||
public static final String REDISSON_CONFIG_PATH = CONFIG_PREFIX + "config";
|
||||
|
||||
protected RedissonClient redisson;
|
||||
private Settings settings;
|
||||
|
||||
@Override
|
||||
public void start(Settings settings, Properties properties) throws CacheException {
|
||||
Config config = null;
|
||||
if (!properties.containsKey(REDISSON_CONFIG_PATH)) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.json");
|
||||
if (config == null) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.yaml");
|
||||
}
|
||||
} else {
|
||||
String configPath = ConfigurationHelper.getString(REDISSON_CONFIG_PATH, properties);
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), configPath);
|
||||
if (config == null) {
|
||||
config = loadConfig(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
throw new CacheException("Unable to locate Redisson configuration");
|
||||
}
|
||||
|
||||
this.redisson = Redisson.create(config);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
private Config loadConfig(String configPath) {
|
||||
try {
|
||||
return Config.fromJSON(new File(configPath));
|
||||
} catch (IOException e) {
|
||||
// trying next format
|
||||
try {
|
||||
return Config.fromYAML(new File(configPath));
|
||||
} catch (IOException e1) {
|
||||
throw new CacheException("Can't parse default yaml config", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Config loadConfig(ClassLoader classLoader, String fileName) {
|
||||
Config config = null;
|
||||
try {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
config = Config.fromJSON(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CacheException("Can't parse json config", e);
|
||||
}
|
||||
if (config == null) {
|
||||
try {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
config = Config.fromYAML(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CacheException("Can't parse yaml config", e);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
redisson.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimalPutsEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessType getDefaultAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
long time = System.currentTimeMillis() << 12;
|
||||
return redisson.getScript(LongCodec.INSTANCE).eval(RScript.Mode.READ_WRITE,
|
||||
"local currentTime = redis.call('get', KEYS[1]);"
|
||||
+ "if currentTime == false then "
|
||||
+ "redis.call('set', KEYS[1], ARGV[1]); "
|
||||
+ "return ARGV[1]; "
|
||||
+ "end;"
|
||||
+ "local nextValue = math.max(tonumber(ARGV[1]), tonumber(currentTime) + 1); "
|
||||
+ "redis.call('set', KEYS[1], nextValue); "
|
||||
+ "return nextValue;",
|
||||
RScript.ReturnType.INTEGER, Arrays.<Object>asList("redisson-hibernate-timestamp"), time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
|
||||
throws CacheException {
|
||||
log.debug("Building entity cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonEntityRegion(mapCache, this, metadata, settings, properties, ENTITY_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata)
|
||||
throws CacheException {
|
||||
log.debug("Building naturalId cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonNaturalIdRegion(mapCache, this, metadata, settings, properties, NATURAL_ID_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
|
||||
CacheDataDescription metadata) throws CacheException {
|
||||
log.debug("Building collection cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonCollectionRegion(mapCache, this, metadata, settings, properties, COLLECTION_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
|
||||
log.debug("Building query cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonQueryRegion(mapCache, this, properties, QUERY_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
|
||||
log.debug("Building timestamps cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonTimestampsRegion(mapCache, this, properties, TIMESTAMPS_DEF);
|
||||
}
|
||||
|
||||
protected RMapCache<Object, Object> getCache(String regionName, Properties properties) {
|
||||
return redisson.getMapCache(regionName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonStrategyRegistrationProvider implements StrategyRegistrationProvider {
|
||||
|
||||
@Override
|
||||
public Iterable<StrategyRegistration> getStrategyRegistrations() {
|
||||
return Collections.<StrategyRegistration>singleton(new SimpleStrategyRegistrationImpl(
|
||||
RegionFactory.class,
|
||||
RedissonRegionFactory.class,
|
||||
"redisson",
|
||||
RedissonRegionFactory.class.getName(),
|
||||
RedissonRegionFactory.class.getSimpleName()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TransactionalDataRegion;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class BaseRegion implements TransactionalDataRegion, GeneralDataRegion {
|
||||
|
||||
RMapCache<Object, Object> mapCache;
|
||||
RegionFactory regionFactory;
|
||||
CacheDataDescription metadata;
|
||||
|
||||
int ttl;
|
||||
int maxIdle;
|
||||
|
||||
public BaseRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory, CacheDataDescription metadata, Properties properties, String defaultKey) {
|
||||
super();
|
||||
this.mapCache = mapCache;
|
||||
this.regionFactory = regionFactory;
|
||||
this.metadata = metadata;
|
||||
|
||||
String maxEntries = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_ENTRIES_SUFFIX);
|
||||
if (maxEntries != null) {
|
||||
mapCache.setMaxSize(Integer.valueOf(maxEntries));
|
||||
}
|
||||
String timeToLive = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.TTL_SUFFIX);
|
||||
if (timeToLive != null) {
|
||||
ttl = Integer.valueOf(timeToLive);
|
||||
}
|
||||
String maxIdleTime = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_IDLE_SUFFIX);
|
||||
if (maxIdleTime != null) {
|
||||
maxIdle = Integer.valueOf(maxIdleTime);
|
||||
}
|
||||
}
|
||||
|
||||
private String getProperty(Properties properties, String name, String defaultKey, String suffix) {
|
||||
String value = properties.getProperty(RedissonRegionFactory.CONFIG_PREFIX + name + suffix);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
String defValue = properties.getProperty(RedissonRegionFactory.CONFIG_PREFIX + defaultKey + suffix);
|
||||
if (defValue != null) {
|
||||
return defValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAware() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheDataDescription getCacheDataDescription() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mapCache.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws CacheException {
|
||||
try {
|
||||
mapCache.clear();
|
||||
mapCache.destroy();
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object key) {
|
||||
try {
|
||||
return mapCache.containsKey(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSizeInMemory() {
|
||||
return mapCache.sizeInMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getElementCountInMemory() {
|
||||
return mapCache.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getElementCountOnDisk() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, ?> toMap() {
|
||||
return Collections.unmodifiableMap(mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
return regionFactory.nextTimestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeout() {
|
||||
return (1 << 12) * 60000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) throws CacheException {
|
||||
try {
|
||||
return mapCache.get(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
try {
|
||||
mapCache.fastPut(key, value, ttl, TimeUnit.MILLISECONDS, maxIdle, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
try {
|
||||
mapCache.fastRemove(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
try {
|
||||
mapCache.clear();
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalCollectionRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonCollectionRegion extends BaseRegion implements CollectionRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonCollectionRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteCollectionRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalEntityRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonEntityRegion extends BaseRegion implements EntityRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonEntityRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteEntityRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalNaturalIdRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonNaturalIdRegion extends BaseRegion implements NaturalIdRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonNaturalIdRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteNaturalIdRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.spi.QueryResultsRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonQueryRegion extends BaseRegion implements QueryResultsRegion {
|
||||
|
||||
public RedissonQueryRegion(RMapCache<Object, Object> mapCache,
|
||||
RegionFactory regionFactory, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, null, properties, defaultKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TimestampsRegion;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonTimestampsRegion extends BaseRegion implements TimestampsRegion {
|
||||
|
||||
public RedissonTimestampsRegion(RMapCache<Object, Object> mapCache,
|
||||
RegionFactory regionFactory, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, null, properties, defaultKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,355 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.TransactionalDataRegion;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Strong Liu
|
||||
*
|
||||
*/
|
||||
public class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy {
|
||||
|
||||
private final UUID uuid = UUID.randomUUID();
|
||||
private final AtomicLong nextLockId = new AtomicLong();
|
||||
RMapCache<Object, Object> mapCache;
|
||||
|
||||
public AbstractReadWriteAccessStrategy(Settings settings, GeneralDataRegion region, RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region);
|
||||
this.mapCache = mapCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
RLock readLock = mapCache.getReadWriteLock(key).readLock();
|
||||
readLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get( key );
|
||||
|
||||
if (item != null && item.isReadable(txTimestamp)) {
|
||||
return item.getValue();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(key);
|
||||
Comparator<Object> comparator = ((TransactionalDataRegion)region).getCacheDataDescription().getVersionComparator();
|
||||
boolean writeable = item == null || item.isWriteable(txTimestamp, version, comparator);
|
||||
if (writeable) {
|
||||
region.put(key, new Item(value, version, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get( key );
|
||||
long timeout = region.nextTimestamp() + region.getTimeout();
|
||||
|
||||
Lock lock;
|
||||
if (item == null) {
|
||||
lock = new Lock(timeout, uuid, nextLockId.getAndIncrement(), version);
|
||||
} else {
|
||||
lock = item.lock(timeout, uuid, nextLockId.getAndIncrement());
|
||||
}
|
||||
region.put( key, lock );
|
||||
return lock;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
decrementLock(key, (Lock)item);
|
||||
} else {
|
||||
handleLockExpiry(key, item);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock and re-put the given key, lock combination.
|
||||
*/
|
||||
protected void decrementLock(Object key, Lock lock) {
|
||||
lock.unlock(region.nextTimestamp());
|
||||
region.put(key, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the timeout of a previous lock mapped to this key
|
||||
*/
|
||||
protected void handleLockExpiry(Object key, Lockable lock) {
|
||||
long ts = region.nextTimestamp() + region.getTimeout();
|
||||
// create new lock that times out immediately
|
||||
Lock newLock = new Lock(ts, uuid, nextLockId.getAndIncrement(), null);
|
||||
newLock.unlock(ts);
|
||||
region.put(key, newLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface type implemented by all wrapper objects in the cache.
|
||||
*/
|
||||
public interface Lockable {
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the enclosed value can be read by a transaction started at the given time.
|
||||
*/
|
||||
public boolean isReadable(long txTimestamp);
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the enclosed value can be replaced with one of the given version by a
|
||||
* transaction started at the given time.
|
||||
*/
|
||||
public boolean isWriteable(long txTimestamp, Object version, Comparator<Object> versionComparator);
|
||||
|
||||
/**
|
||||
* Returns the enclosed value.
|
||||
*/
|
||||
public Object getValue();
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the given lock can be unlocked using the given SoftLock instance as a handle.
|
||||
*/
|
||||
public boolean isUnlockable(SoftLock lock);
|
||||
|
||||
/**
|
||||
* Locks this entry, stamping it with the UUID and lockId given, with the lock timeout occuring at the specified
|
||||
* time. The returned Lock object can be used to unlock the entry in the future.
|
||||
*/
|
||||
public Lock lock(long timeout, UUID uuid, long lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper type representing unlocked items.
|
||||
*/
|
||||
public final static class Item implements Serializable, Lockable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Object value;
|
||||
private Object version;
|
||||
private long timestamp;
|
||||
|
||||
/**
|
||||
* Creates an unlocked item wrapping the given value with a version and creation timestamp.
|
||||
*/
|
||||
public Item(Object value, Object version, long timestamp) {
|
||||
this.value = value;
|
||||
this.version = version;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(long txTimestamp) {
|
||||
return txTimestamp > timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(long txTimestamp, Object newVersion, Comparator<Object> versionComparator) {
|
||||
return version != null && versionComparator.compare( version, newVersion ) < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnlockable(SoftLock lock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock lock(long timeout, UUID uuid, long lockId) {
|
||||
return new Lock(timeout, uuid, lockId, version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper type representing locked items.
|
||||
*/
|
||||
public final static class Lock implements Serializable, Lockable, SoftLock {
|
||||
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private UUID sourceUuid;
|
||||
private long lockId;
|
||||
private Object version;
|
||||
|
||||
private long timeout;
|
||||
private boolean concurrent;
|
||||
private int multiplicity = 1;
|
||||
private long unlockTimestamp;
|
||||
|
||||
/**
|
||||
* Creates a locked item with the given identifiers and object version.
|
||||
*/
|
||||
public Lock(long timeout, UUID sourceUuid, long lockId, Object version) {
|
||||
this.timeout = timeout;
|
||||
this.lockId = lockId;
|
||||
this.version = version;
|
||||
this.sourceUuid = sourceUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(long txTimestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) {
|
||||
if ( txTimestamp > timeout ) {
|
||||
// if timedout then allow write
|
||||
return true;
|
||||
}
|
||||
if ( multiplicity > 0 ) {
|
||||
// if still locked then disallow write
|
||||
return false;
|
||||
}
|
||||
return version == null ? txTimestamp > unlockTimestamp : versionComparator.compare(
|
||||
version,
|
||||
newVersion
|
||||
) < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnlockable(SoftLock lock) {
|
||||
return equals( lock );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( o == this ) {
|
||||
return true;
|
||||
}
|
||||
else if ( o instanceof Lock ) {
|
||||
return ( lockId == ( (Lock) o ).lockId ) && sourceUuid.equals( ( (Lock) o ).sourceUuid );
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = ( sourceUuid != null ? sourceUuid.hashCode() : 0 );
|
||||
int temp = (int) lockId;
|
||||
for ( int i = 1; i < Long.SIZE / Integer.SIZE; i++ ) {
|
||||
temp ^= ( lockId >>> ( i * Integer.SIZE ) );
|
||||
}
|
||||
return hash + temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Lock has been concurrently locked by more than one transaction.
|
||||
*/
|
||||
public boolean wasLockedConcurrently() {
|
||||
return concurrent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock lock(long timeout, UUID uuid, long lockId) {
|
||||
concurrent = true;
|
||||
multiplicity++;
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks this Lock, and timestamps the unlock event.
|
||||
*/
|
||||
public void unlock(long timestamp) {
|
||||
if ( --multiplicity == 0 ) {
|
||||
unlockTimestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder( "Lock Source-UUID:" + sourceUuid + " Lock-ID:" + lockId );
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.RegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
abstract class BaseRegionAccessStrategy implements RegionAccessStrategy {
|
||||
|
||||
GeneralDataRegion region;
|
||||
Settings settings;
|
||||
|
||||
BaseRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
this.settings = settings;
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return putFromLoad( key, value, txTimestamp, version, settings.isMinimalPutsEnabled() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll() throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
remove(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
unlockItem(key, lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value) throws CacheException {
|
||||
remove(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, SoftLock lock) throws CacheException {
|
||||
unlockItem(key, lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value) throws CacheException {
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value) throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, SoftLock lock) throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadWriteCollectionRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public ReadWriteCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region,
|
||||
RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Strong Liu
|
||||
*
|
||||
*/
|
||||
public class ReadWriteEntityRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public ReadWriteEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region, RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(key);
|
||||
if (item == null) {
|
||||
region.put(key, new Item(value, version, region.nextTimestamp()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
Lock lockItem = (Lock) item;
|
||||
if (lockItem.wasLockedConcurrently()) {
|
||||
decrementLock( key, lockItem );
|
||||
return false;
|
||||
} else {
|
||||
region.put( key, new Item(value, currentVersion, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
handleLockExpiry( key, item );
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Eric Dalquist
|
||||
*
|
||||
*/
|
||||
public class ReadWriteNaturalIdRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public ReadWriteNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region,
|
||||
RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(key);
|
||||
if (item == null) {
|
||||
region.put(key, new Item(value, null, region.nextTimestamp()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, SoftLock lock) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
Lock lockItem = (Lock) item;
|
||||
if (lockItem.wasLockedConcurrently()) {
|
||||
decrementLock(key, lockItem);
|
||||
return false;
|
||||
} else {
|
||||
region.put(key, new Item(value, null, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
handleLockExpiry(key, item);
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public TransactionalCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public TransactionalEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
return insert(key, value, currentVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public TransactionalNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(Object key, Object value) throws CacheException {
|
||||
region.put(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value) throws CacheException {
|
||||
return insert(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(Object key, Object value, SoftLock lock) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.redisson.hibernate.RedissonStrategyRegistrationProvider
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<blueprint default-activation="eager"
|
||||
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<bean id="strategyRegistrationProvider" class="org.redisson.hibernate.RedissonStrategyRegistrationProvider"/>
|
||||
|
||||
<service ref="strategyRegistrationProvider" interface="org.hibernate.boot.registry.selector.StrategyRegistrationProvider"/>
|
||||
|
||||
</blueprint>
|
@ -0,0 +1,84 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries(@NamedQuery(name = "testQuery", query = "from ItemReadWrite where name = :name"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||
@NaturalIdCache
|
||||
public class ItemReadWrite {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@NaturalId
|
||||
private String nid;
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(name = "Entries", joinColumns = @JoinColumn(name="Item_id"))
|
||||
@Column(name = "entry", nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item_entries")
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
|
||||
public ItemReadWrite() {
|
||||
}
|
||||
|
||||
public ItemReadWrite(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries(@NamedQuery(name = "testQuery", query = "from ItemTransactional where name = :name"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "item")
|
||||
@NaturalIdCache
|
||||
public class ItemTransactional {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@NaturalId
|
||||
private String nid;
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(name = "Entries", joinColumns = @JoinColumn(name="Item_id"))
|
||||
@Column(name = "entry", nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "item_entries")
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
|
||||
public ItemTransactional() {
|
||||
}
|
||||
|
||||
public ItemTransactional(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadWriteTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { ItemReadWrite.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
|
||||
cfg.setProperty("hibernate.cache.redisson.item.eviction.max_entries", "100");
|
||||
cfg.setProperty("hibernate.cache.redisson.item.expiration.time_to_live", "1500");
|
||||
cfg.setProperty("hibernate.cache.redisson.item.expiration.max_idle_time", "1000");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeToLive() throws InterruptedException {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Thread.sleep(900);
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(0, stats.getSecondLevelCacheStatistics("item").getMissCount());
|
||||
|
||||
Thread.sleep(600);
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getMissCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query = s.getNamedQuery("testQuery");
|
||||
query.setCacheable(true);
|
||||
query.setCacheRegion("myTestQuery");
|
||||
query.setParameter("name", "data");
|
||||
item = (ItemReadWrite) query.uniqueResult();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query2 = s.getNamedQuery("testQuery");
|
||||
query2.setCacheable(true);
|
||||
query2.setCacheRegion("myTestQuery");
|
||||
query2.setParameter("name", "data");
|
||||
item = (ItemReadWrite) query2.uniqueResult();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollection() {
|
||||
Long id = null;
|
||||
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
id = (Long) s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getHitCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalId() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.setNid("123");
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.bySimpleNaturalId(ItemReadWrite.class).load("123");
|
||||
assertThat(item).isNotNull();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getHitCount());
|
||||
|
||||
sessionFactory().getStatistics().logSummary();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithRefreshThenRollback() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
item.setName("newdata");
|
||||
s.update(item);
|
||||
s.flush();
|
||||
s.refresh(item);
|
||||
s.getTransaction().rollback();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { ItemTransactional.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query = s.getNamedQuery("testQuery");
|
||||
query.setCacheable(true);
|
||||
query.setCacheRegion("myTestQuery");
|
||||
query.setParameter("name", "data");
|
||||
item = (ItemTransactional) query.uniqueResult();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query2 = s.getNamedQuery("testQuery");
|
||||
query2.setCacheable(true);
|
||||
query2.setCacheRegion("myTestQuery");
|
||||
query2.setParameter("name", "data");
|
||||
item = (ItemTransactional) query2.uniqueResult();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollection() {
|
||||
Long id = null;
|
||||
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
id = (Long) s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getHitCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalId() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.setNid("123");
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.bySimpleNaturalId(ItemTransactional.class).load("123");
|
||||
assertThat(item).isNotNull();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getHitCount());
|
||||
|
||||
sessionFactory().getStatistics().logSummary();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithRefreshThenRollback() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
item.setName("newdata");
|
||||
s.update(item);
|
||||
s.flush();
|
||||
s.refresh(item);
|
||||
s.getTransaction().rollback();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"singleServerConfig":{
|
||||
"address": "redis://127.0.0.1:6379"
|
||||
},
|
||||
"codec":{
|
||||
"class":"org.redisson.codec.FstCodec"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"singleServerConfig":{
|
||||
"address": "redis://127.0.0.1:6379"
|
||||
},
|
||||
"codec":{
|
||||
"class":"org.redisson.codec.FstCodec"
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-hibernate</artifactId>
|
||||
<version>2.14.2-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>redisson-hibernate-5</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Redisson/Hibernate-5.0.x-5.1.x</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>de.ruedigermoeller</groupId>
|
||||
<artifactId>fst</artifactId>
|
||||
<version>2.54</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>5.1.16.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-testing</artifactId>
|
||||
<version>5.1.16.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<basedir>${basedir}</basedir>
|
||||
<header>${basedir}/../../header.txt</header>
|
||||
<quiet>false</quiet>
|
||||
<failIfMissing>true</failIfMissing>
|
||||
<aggregate>false</aggregate>
|
||||
<includes>
|
||||
<include>src/main/java/org/redisson/</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>target/**</exclude>
|
||||
</excludes>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<mapping>
|
||||
<java>JAVADOC_STYLE</java>
|
||||
</mapping>
|
||||
<strictCheck>true</strictCheck>
|
||||
<useDefaultMapping>true</useDefaultMapping>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.QueryResultsRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TimestampsRegion;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RScript;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.client.codec.LongCodec;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.hibernate.region.RedissonCollectionRegion;
|
||||
import org.redisson.hibernate.region.RedissonEntityRegion;
|
||||
import org.redisson.hibernate.region.RedissonNaturalIdRegion;
|
||||
import org.redisson.hibernate.region.RedissonQueryRegion;
|
||||
import org.redisson.hibernate.region.RedissonTimestampsRegion;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonRegionFactory implements RegionFactory {
|
||||
|
||||
private static final Logger log = Logger.getLogger( RedissonRegionFactory.class );
|
||||
|
||||
private static final long serialVersionUID = 3785315696581773811L;
|
||||
|
||||
public static final String QUERY_DEF = "query";
|
||||
|
||||
public static final String COLLECTION_DEF = "collection";
|
||||
|
||||
public static final String ENTITY_DEF = "entity";
|
||||
|
||||
public static final String NATURAL_ID_DEF = "naturalid";
|
||||
|
||||
public static final String TIMESTAMPS_DEF = "timestamps";
|
||||
|
||||
public static final String MAX_ENTRIES_SUFFIX = ".eviction.max_entries";
|
||||
|
||||
public static final String TTL_SUFFIX = ".expiration.time_to_live";
|
||||
|
||||
public static final String MAX_IDLE_SUFFIX = ".expiration.max_idle_time";
|
||||
|
||||
public static final String CONFIG_PREFIX = "hibernate.cache.redisson.";
|
||||
|
||||
public static final String REDISSON_CONFIG_PATH = CONFIG_PREFIX + "config";
|
||||
|
||||
protected RedissonClient redisson;
|
||||
private Settings settings;
|
||||
|
||||
@Override
|
||||
public void start(SessionFactoryOptions settings, Properties properties) throws CacheException {
|
||||
Config config = null;
|
||||
if (!properties.containsKey(REDISSON_CONFIG_PATH)) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.json");
|
||||
if (config == null) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.yaml");
|
||||
}
|
||||
} else {
|
||||
String configPath = ConfigurationHelper.getString(REDISSON_CONFIG_PATH, properties);
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), configPath);
|
||||
if (config == null) {
|
||||
config = loadConfig(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
throw new CacheException("Unable to locate Redisson configuration");
|
||||
}
|
||||
|
||||
this.redisson = Redisson.create(config);
|
||||
this.settings = new Settings(settings);
|
||||
}
|
||||
|
||||
private Config loadConfig(String configPath) {
|
||||
try {
|
||||
return Config.fromJSON(new File(configPath));
|
||||
} catch (IOException e) {
|
||||
// trying next format
|
||||
try {
|
||||
return Config.fromYAML(new File(configPath));
|
||||
} catch (IOException e1) {
|
||||
throw new CacheException("Can't parse default yaml config", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Config loadConfig(ClassLoader classLoader, String fileName) {
|
||||
Config config = null;
|
||||
try {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
config = Config.fromJSON(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CacheException("Can't parse json config", e);
|
||||
}
|
||||
if (config == null) {
|
||||
try {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
config = Config.fromYAML(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CacheException("Can't parse yaml config", e);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
redisson.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimalPutsEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessType getDefaultAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
long time = System.currentTimeMillis() << 12;
|
||||
return redisson.getScript(LongCodec.INSTANCE).eval(RScript.Mode.READ_WRITE,
|
||||
"local currentTime = redis.call('get', KEYS[1]);"
|
||||
+ "if currentTime == false then "
|
||||
+ "redis.call('set', KEYS[1], ARGV[1]); "
|
||||
+ "return ARGV[1]; "
|
||||
+ "end;"
|
||||
+ "local nextValue = math.max(tonumber(ARGV[1]), tonumber(currentTime) + 1); "
|
||||
+ "redis.call('set', KEYS[1], nextValue); "
|
||||
+ "return nextValue;",
|
||||
RScript.ReturnType.INTEGER, Arrays.<Object>asList("redisson-hibernate-timestamp"), time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
|
||||
throws CacheException {
|
||||
log.debug("Building entity cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonEntityRegion(mapCache, this, metadata, settings, properties, ENTITY_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata)
|
||||
throws CacheException {
|
||||
log.debug("Building naturalId cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonNaturalIdRegion(mapCache, this, metadata, settings, properties, NATURAL_ID_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
|
||||
CacheDataDescription metadata) throws CacheException {
|
||||
log.debug("Building collection cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonCollectionRegion(mapCache, this, metadata, settings, properties, COLLECTION_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
|
||||
log.debug("Building query cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonQueryRegion(mapCache, this, properties, QUERY_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
|
||||
log.debug("Building timestamps cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonTimestampsRegion(mapCache, this, properties, TIMESTAMPS_DEF);
|
||||
}
|
||||
|
||||
protected RMapCache<Object, Object> getCache(String regionName, Properties properties) {
|
||||
return redisson.getMapCache(regionName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonStrategyRegistrationProvider implements StrategyRegistrationProvider {
|
||||
|
||||
@Override
|
||||
public Iterable<StrategyRegistration> getStrategyRegistrations() {
|
||||
return Collections.<StrategyRegistration>singleton(new SimpleStrategyRegistrationImpl(
|
||||
RegionFactory.class,
|
||||
RedissonRegionFactory.class,
|
||||
"redisson",
|
||||
RedissonRegionFactory.class.getName(),
|
||||
RedissonRegionFactory.class.getSimpleName()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TransactionalDataRegion;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class BaseRegion implements TransactionalDataRegion, GeneralDataRegion {
|
||||
|
||||
RMapCache<Object, Object> mapCache;
|
||||
RegionFactory regionFactory;
|
||||
CacheDataDescription metadata;
|
||||
|
||||
int ttl;
|
||||
int maxIdle;
|
||||
|
||||
public BaseRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory, CacheDataDescription metadata, Properties properties, String defaultKey) {
|
||||
super();
|
||||
this.mapCache = mapCache;
|
||||
this.regionFactory = regionFactory;
|
||||
this.metadata = metadata;
|
||||
|
||||
String maxEntries = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_ENTRIES_SUFFIX);
|
||||
if (maxEntries != null) {
|
||||
mapCache.setMaxSize(Integer.valueOf(maxEntries));
|
||||
}
|
||||
String timeToLive = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.TTL_SUFFIX);
|
||||
if (timeToLive != null) {
|
||||
ttl = Integer.valueOf(timeToLive);
|
||||
}
|
||||
String maxIdleTime = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_IDLE_SUFFIX);
|
||||
if (maxIdleTime != null) {
|
||||
maxIdle = Integer.valueOf(maxIdleTime);
|
||||
}
|
||||
}
|
||||
|
||||
private String getProperty(Properties properties, String name, String defaultKey, String suffix) {
|
||||
String value = properties.getProperty(RedissonRegionFactory.CONFIG_PREFIX + name + suffix);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
String defValue = properties.getProperty(RedissonRegionFactory.CONFIG_PREFIX + defaultKey + suffix);
|
||||
if (defValue != null) {
|
||||
return defValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAware() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheDataDescription getCacheDataDescription() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mapCache.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws CacheException {
|
||||
try {
|
||||
mapCache.clear();
|
||||
mapCache.destroy();
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object key) {
|
||||
try {
|
||||
return mapCache.containsKey(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSizeInMemory() {
|
||||
return mapCache.sizeInMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getElementCountInMemory() {
|
||||
return mapCache.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getElementCountOnDisk() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, ?> toMap() {
|
||||
return Collections.unmodifiableMap(mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
return regionFactory.nextTimestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeout() {
|
||||
return (1 << 12) * 60000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key) throws CacheException {
|
||||
try {
|
||||
return mapCache.get(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
try {
|
||||
mapCache.fastPut(key, value, ttl, TimeUnit.MILLISECONDS, maxIdle, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
try {
|
||||
mapCache.fastRemove(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
try {
|
||||
mapCache.clear();
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalCollectionRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonCollectionRegion extends BaseRegion implements CollectionRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonCollectionRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteCollectionRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalEntityRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonEntityRegion extends BaseRegion implements EntityRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonEntityRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteEntityRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalNaturalIdRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonNaturalIdRegion extends BaseRegion implements NaturalIdRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonNaturalIdRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteNaturalIdRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.spi.QueryResultsRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonQueryRegion extends BaseRegion implements QueryResultsRegion {
|
||||
|
||||
public RedissonQueryRegion(RMapCache<Object, Object> mapCache,
|
||||
RegionFactory regionFactory, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, null, properties, defaultKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TimestampsRegion;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonTimestampsRegion extends BaseRegion implements TimestampsRegion {
|
||||
|
||||
public RedissonTimestampsRegion(RMapCache<Object, Object> mapCache,
|
||||
RegionFactory regionFactory, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, null, properties, defaultKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,356 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.TransactionalDataRegion;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Strong Liu
|
||||
*
|
||||
*/
|
||||
public class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy {
|
||||
|
||||
private final UUID uuid = UUID.randomUUID();
|
||||
private final AtomicLong nextLockId = new AtomicLong();
|
||||
RMapCache<Object, Object> mapCache;
|
||||
|
||||
public AbstractReadWriteAccessStrategy(Settings settings, GeneralDataRegion region, RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region);
|
||||
this.mapCache = mapCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
RLock readLock = mapCache.getReadWriteLock(key).readLock();
|
||||
readLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
|
||||
if (item != null && item.isReadable(txTimestamp)) {
|
||||
return item.getValue();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
Comparator<Object> comparator = ((TransactionalDataRegion)region).getCacheDataDescription().getVersionComparator();
|
||||
boolean writeable = item == null || item.isWriteable(txTimestamp, version, comparator);
|
||||
if (writeable) {
|
||||
region.put(session, key, new Item(value, version, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
long timeout = region.nextTimestamp() + region.getTimeout();
|
||||
|
||||
Lock lock;
|
||||
if (item == null) {
|
||||
lock = new Lock(timeout, uuid, nextLockId.getAndIncrement(), version);
|
||||
} else {
|
||||
lock = item.lock(timeout, uuid, nextLockId.getAndIncrement());
|
||||
}
|
||||
region.put(session, key, lock);
|
||||
return lock;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
decrementLock(session, key, (Lock)item);
|
||||
} else {
|
||||
handleLockExpiry(session, key, item);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock and re-put the given key, lock combination.
|
||||
*/
|
||||
protected void decrementLock(SessionImplementor session, Object key, Lock lock) {
|
||||
lock.unlock(region.nextTimestamp());
|
||||
region.put(session, key, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the timeout of a previous lock mapped to this key
|
||||
*/
|
||||
protected void handleLockExpiry(SessionImplementor session, Object key, Lockable lock) {
|
||||
long ts = region.nextTimestamp() + region.getTimeout();
|
||||
// create new lock that times out immediately
|
||||
Lock newLock = new Lock(ts, uuid, nextLockId.getAndIncrement(), null);
|
||||
newLock.unlock(ts);
|
||||
region.put(session, key, newLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface type implemented by all wrapper objects in the cache.
|
||||
*/
|
||||
public interface Lockable {
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the enclosed value can be read by a transaction started at the given time.
|
||||
*/
|
||||
public boolean isReadable(long txTimestamp);
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the enclosed value can be replaced with one of the given version by a
|
||||
* transaction started at the given time.
|
||||
*/
|
||||
public boolean isWriteable(long txTimestamp, Object version, Comparator<Object> versionComparator);
|
||||
|
||||
/**
|
||||
* Returns the enclosed value.
|
||||
*/
|
||||
public Object getValue();
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the given lock can be unlocked using the given SoftLock instance as a handle.
|
||||
*/
|
||||
public boolean isUnlockable(SoftLock lock);
|
||||
|
||||
/**
|
||||
* Locks this entry, stamping it with the UUID and lockId given, with the lock timeout occuring at the specified
|
||||
* time. The returned Lock object can be used to unlock the entry in the future.
|
||||
*/
|
||||
public Lock lock(long timeout, UUID uuid, long lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper type representing unlocked items.
|
||||
*/
|
||||
public final static class Item implements Serializable, Lockable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Object value;
|
||||
private Object version;
|
||||
private long timestamp;
|
||||
|
||||
/**
|
||||
* Creates an unlocked item wrapping the given value with a version and creation timestamp.
|
||||
*/
|
||||
public Item(Object value, Object version, long timestamp) {
|
||||
this.value = value;
|
||||
this.version = version;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(long txTimestamp) {
|
||||
return txTimestamp > timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(long txTimestamp, Object newVersion, Comparator<Object> versionComparator) {
|
||||
return version != null && versionComparator.compare( version, newVersion ) < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnlockable(SoftLock lock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock lock(long timeout, UUID uuid, long lockId) {
|
||||
return new Lock(timeout, uuid, lockId, version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper type representing locked items.
|
||||
*/
|
||||
public final static class Lock implements Serializable, Lockable, SoftLock {
|
||||
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private UUID sourceUuid;
|
||||
private long lockId;
|
||||
private Object version;
|
||||
|
||||
private long timeout;
|
||||
private boolean concurrent;
|
||||
private int multiplicity = 1;
|
||||
private long unlockTimestamp;
|
||||
|
||||
/**
|
||||
* Creates a locked item with the given identifiers and object version.
|
||||
*/
|
||||
public Lock(long timeout, UUID sourceUuid, long lockId, Object version) {
|
||||
this.timeout = timeout;
|
||||
this.lockId = lockId;
|
||||
this.version = version;
|
||||
this.sourceUuid = sourceUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(long txTimestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) {
|
||||
if ( txTimestamp > timeout ) {
|
||||
// if timedout then allow write
|
||||
return true;
|
||||
}
|
||||
if ( multiplicity > 0 ) {
|
||||
// if still locked then disallow write
|
||||
return false;
|
||||
}
|
||||
return version == null ? txTimestamp > unlockTimestamp : versionComparator.compare(
|
||||
version,
|
||||
newVersion
|
||||
) < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnlockable(SoftLock lock) {
|
||||
return equals( lock );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( o == this ) {
|
||||
return true;
|
||||
}
|
||||
else if ( o instanceof Lock ) {
|
||||
return ( lockId == ( (Lock) o ).lockId ) && sourceUuid.equals( ( (Lock) o ).sourceUuid );
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = ( sourceUuid != null ? sourceUuid.hashCode() : 0 );
|
||||
int temp = (int) lockId;
|
||||
for ( int i = 1; i < Long.SIZE / Integer.SIZE; i++ ) {
|
||||
temp ^= ( lockId >>> ( i * Integer.SIZE ) );
|
||||
}
|
||||
return hash + temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Lock has been concurrently locked by more than one transaction.
|
||||
*/
|
||||
public boolean wasLockedConcurrently() {
|
||||
return concurrent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock lock(long timeout, UUID uuid, long lockId) {
|
||||
concurrent = true;
|
||||
multiplicity++;
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks this Lock, and timestamps the unlock event.
|
||||
*/
|
||||
public void unlock(long timestamp) {
|
||||
if ( --multiplicity == 0 ) {
|
||||
unlockTimestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder( "Lock Source-UUID:" + sourceUuid + " Lock-ID:" + lockId );
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.RegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
abstract class BaseRegionAccessStrategy implements RegionAccessStrategy {
|
||||
|
||||
GeneralDataRegion region;
|
||||
Settings settings;
|
||||
|
||||
BaseRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
this.settings = settings;
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return putFromLoad(session, key, value, txTimestamp, version, settings.isMinimalPutsEnabled() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SessionImplementor session, Object key) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll() throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SessionImplementor session, Object key) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory,
|
||||
String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetCollectionId( cacheKey );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
remove(session, key);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
unlockItem(session, key, lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SessionImplementor session, Object key) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetEntityId( cacheKey );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
remove(session, key);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SessionImplementor session, Object key, Object value, SoftLock lock) throws CacheException {
|
||||
unlockItem(session, key, lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SessionImplementor session, Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
|
||||
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SessionImplementor session, Object key, Object value, SoftLock lock) throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
|
||||
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadWriteCollectionRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public ReadWriteCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region,
|
||||
RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Strong Liu
|
||||
*
|
||||
*/
|
||||
public class ReadWriteEntityRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public ReadWriteEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region, RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
if (item == null) {
|
||||
region.put(session, key, new Item(value, version, region.nextTimestamp()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
Lock lockItem = (Lock) item;
|
||||
if (lockItem.wasLockedConcurrently()) {
|
||||
decrementLock(session, key, lockItem );
|
||||
return false;
|
||||
} else {
|
||||
region.put(session, key, new Item(value, currentVersion, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
handleLockExpiry(session, key, item );
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateEntityKey(id, persister, factory, tenantIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Eric Dalquist
|
||||
*
|
||||
*/
|
||||
public class ReadWriteNaturalIdRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public ReadWriteNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region,
|
||||
RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
if (item == null) {
|
||||
region.put(session, key, new Item(value, null, region.nextTimestamp()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SessionImplementor session, Object key, Object value, SoftLock lock) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
Lock lockItem = (Lock) item;
|
||||
if (lockItem.wasLockedConcurrently()) {
|
||||
decrementLock(session, key, lockItem);
|
||||
return false;
|
||||
} else {
|
||||
region.put(session, key, new Item(value, null, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
handleLockExpiry(session, key, item);
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
|
||||
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public TransactionalCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SessionImplementor session, Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public TransactionalEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SessionImplementor session, Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
return insert(session, key, value, currentVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateEntityKey(id, persister, factory, tenantIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public TransactionalNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SessionImplementor session, Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SessionImplementor session, Object key, Object value) throws CacheException {
|
||||
return insert(session, key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SessionImplementor session, Object key, Object value, SoftLock lock) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
|
||||
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.redisson.hibernate.RedissonStrategyRegistrationProvider
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<blueprint default-activation="eager"
|
||||
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<bean id="strategyRegistrationProvider" class="org.redisson.hibernate.RedissonStrategyRegistrationProvider"/>
|
||||
|
||||
<service ref="strategyRegistrationProvider" interface="org.hibernate.boot.registry.selector.StrategyRegistrationProvider"/>
|
||||
|
||||
</blueprint>
|
@ -0,0 +1,84 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries(@NamedQuery(name = "testQuery", query = "from ItemReadWrite where name = :name"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||
@NaturalIdCache
|
||||
public class ItemReadWrite {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@NaturalId
|
||||
private String nid;
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(name = "Entries", joinColumns = @JoinColumn(name="Item_id"))
|
||||
@Column(name = "entry", nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item_entries")
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
|
||||
public ItemReadWrite() {
|
||||
}
|
||||
|
||||
public ItemReadWrite(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries(@NamedQuery(name = "testQuery", query = "from ItemTransactional where name = :name"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "item")
|
||||
@NaturalIdCache
|
||||
public class ItemTransactional {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@NaturalId
|
||||
private String nid;
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(name = "Entries", joinColumns = @JoinColumn(name="Item_id"))
|
||||
@Column(name = "entry", nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "item_entries")
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
|
||||
public ItemTransactional() {
|
||||
}
|
||||
|
||||
public ItemTransactional(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadWriteTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { ItemReadWrite.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
|
||||
cfg.setProperty("hibernate.cache.redisson.item.eviction.max_entries", "100");
|
||||
cfg.setProperty("hibernate.cache.redisson.item.expiration.time_to_live", "1500");
|
||||
cfg.setProperty("hibernate.cache.redisson.item.expiration.max_idle_time", "1000");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeToLive() throws InterruptedException {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Thread.sleep(900);
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(0, stats.getSecondLevelCacheStatistics("item").getMissCount());
|
||||
|
||||
Thread.sleep(600);
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getMissCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query = s.getNamedQuery("testQuery");
|
||||
query.setCacheable(true);
|
||||
query.setCacheRegion("myTestQuery");
|
||||
query.setParameter("name", "data");
|
||||
item = (ItemReadWrite) query.uniqueResult();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query2 = s.getNamedQuery("testQuery");
|
||||
query2.setCacheable(true);
|
||||
query2.setCacheRegion("myTestQuery");
|
||||
query2.setParameter("name", "data");
|
||||
item = (ItemReadWrite) query2.uniqueResult();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollection() {
|
||||
Long id = null;
|
||||
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
id = (Long) s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getHitCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalId() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.setNid("123");
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.bySimpleNaturalId(ItemReadWrite.class).load("123");
|
||||
assertThat(item).isNotNull();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getHitCount());
|
||||
|
||||
sessionFactory().getStatistics().logSummary();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithRefreshThenRollback() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
item.setName("newdata");
|
||||
s.update(item);
|
||||
s.flush();
|
||||
s.refresh(item);
|
||||
s.getTransaction().rollback();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { ItemTransactional.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query = s.getNamedQuery("testQuery");
|
||||
query.setCacheable(true);
|
||||
query.setCacheRegion("myTestQuery");
|
||||
query.setParameter("name", "data");
|
||||
item = (ItemTransactional) query.uniqueResult();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query2 = s.getNamedQuery("testQuery");
|
||||
query2.setCacheable(true);
|
||||
query2.setCacheRegion("myTestQuery");
|
||||
query2.setParameter("name", "data");
|
||||
item = (ItemTransactional) query2.uniqueResult();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollection() {
|
||||
Long id = null;
|
||||
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
id = (Long) s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getHitCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalId() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.setNid("123");
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.bySimpleNaturalId(ItemTransactional.class).load("123");
|
||||
assertThat(item).isNotNull();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getHitCount());
|
||||
|
||||
sessionFactory().getStatistics().logSummary();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithRefreshThenRollback() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
item.setName("newdata");
|
||||
s.update(item);
|
||||
s.flush();
|
||||
s.refresh(item);
|
||||
s.getTransaction().rollback();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"singleServerConfig":{
|
||||
"address": "redis://127.0.0.1:6379"
|
||||
},
|
||||
"codec":{
|
||||
"class":"org.redisson.codec.FstCodec"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"singleServerConfig":{
|
||||
"address": "redis://127.0.0.1:6379"
|
||||
},
|
||||
"codec":{
|
||||
"class":"org.redisson.codec.FstCodec"
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-hibernate</artifactId>
|
||||
<version>2.14.2-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>redisson-hibernate-52</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Redisson/Hibernate-5.2.x</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>de.ruedigermoeller</groupId>
|
||||
<artifactId>fst</artifactId>
|
||||
<version>2.54</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>5.2.17.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-testing</artifactId>
|
||||
<version>5.2.17.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<basedir>${basedir}</basedir>
|
||||
<header>${basedir}/../../header.txt</header>
|
||||
<quiet>false</quiet>
|
||||
<failIfMissing>true</failIfMissing>
|
||||
<aggregate>false</aggregate>
|
||||
<includes>
|
||||
<include>src/main/java/org/redisson/</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>target/**</exclude>
|
||||
</excludes>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<mapping>
|
||||
<java>JAVADOC_STYLE</java>
|
||||
</mapping>
|
||||
<strictCheck>true</strictCheck>
|
||||
<useDefaultMapping>true</useDefaultMapping>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.QueryResultsRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TimestampsRegion;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RScript;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.client.codec.LongCodec;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.hibernate.region.RedissonCollectionRegion;
|
||||
import org.redisson.hibernate.region.RedissonEntityRegion;
|
||||
import org.redisson.hibernate.region.RedissonNaturalIdRegion;
|
||||
import org.redisson.hibernate.region.RedissonQueryRegion;
|
||||
import org.redisson.hibernate.region.RedissonTimestampsRegion;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonRegionFactory implements RegionFactory {
|
||||
|
||||
private static final Logger log = Logger.getLogger( RedissonRegionFactory.class );
|
||||
|
||||
private static final long serialVersionUID = 3785315696581773811L;
|
||||
|
||||
public static final String QUERY_DEF = "query";
|
||||
|
||||
public static final String COLLECTION_DEF = "collection";
|
||||
|
||||
public static final String ENTITY_DEF = "entity";
|
||||
|
||||
public static final String NATURAL_ID_DEF = "naturalid";
|
||||
|
||||
public static final String TIMESTAMPS_DEF = "timestamps";
|
||||
|
||||
public static final String MAX_ENTRIES_SUFFIX = ".eviction.max_entries";
|
||||
|
||||
public static final String TTL_SUFFIX = ".expiration.time_to_live";
|
||||
|
||||
public static final String MAX_IDLE_SUFFIX = ".expiration.max_idle_time";
|
||||
|
||||
public static final String CONFIG_PREFIX = "hibernate.cache.redisson.";
|
||||
|
||||
public static final String REDISSON_CONFIG_PATH = CONFIG_PREFIX + "config";
|
||||
|
||||
protected RedissonClient redisson;
|
||||
private Settings settings;
|
||||
|
||||
@Override
|
||||
public void start(SessionFactoryOptions settings, Properties properties) throws CacheException {
|
||||
Config config = null;
|
||||
if (!properties.containsKey(REDISSON_CONFIG_PATH)) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.json");
|
||||
if (config == null) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.yaml");
|
||||
}
|
||||
} else {
|
||||
String configPath = ConfigurationHelper.getString(REDISSON_CONFIG_PATH, properties);
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), configPath);
|
||||
if (config == null) {
|
||||
config = loadConfig(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
throw new CacheException("Unable to locate Redisson configuration");
|
||||
}
|
||||
|
||||
this.redisson = Redisson.create(config);
|
||||
this.settings = new Settings(settings);
|
||||
}
|
||||
|
||||
private Config loadConfig(String configPath) {
|
||||
try {
|
||||
return Config.fromJSON(new File(configPath));
|
||||
} catch (IOException e) {
|
||||
// trying next format
|
||||
try {
|
||||
return Config.fromYAML(new File(configPath));
|
||||
} catch (IOException e1) {
|
||||
throw new CacheException("Can't parse default yaml config", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Config loadConfig(ClassLoader classLoader, String fileName) {
|
||||
Config config = null;
|
||||
try {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
config = Config.fromJSON(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CacheException("Can't parse json config", e);
|
||||
}
|
||||
if (config == null) {
|
||||
try {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
config = Config.fromYAML(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CacheException("Can't parse yaml config", e);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
redisson.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimalPutsEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessType getDefaultAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
long time = System.currentTimeMillis() << 12;
|
||||
return redisson.getScript(LongCodec.INSTANCE).eval(RScript.Mode.READ_WRITE,
|
||||
"local currentTime = redis.call('get', KEYS[1]);"
|
||||
+ "if currentTime == false then "
|
||||
+ "redis.call('set', KEYS[1], ARGV[1]); "
|
||||
+ "return ARGV[1]; "
|
||||
+ "end;"
|
||||
+ "local nextValue = math.max(tonumber(ARGV[1]), tonumber(currentTime) + 1); "
|
||||
+ "redis.call('set', KEYS[1], nextValue); "
|
||||
+ "return nextValue;",
|
||||
RScript.ReturnType.INTEGER, Arrays.<Object>asList("redisson-hibernate-timestamp"), time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
|
||||
throws CacheException {
|
||||
log.debug("Building entity cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonEntityRegion(mapCache, this, metadata, settings, properties, ENTITY_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata)
|
||||
throws CacheException {
|
||||
log.debug("Building naturalId cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonNaturalIdRegion(mapCache, this, metadata, settings, properties, NATURAL_ID_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
|
||||
CacheDataDescription metadata) throws CacheException {
|
||||
log.debug("Building collection cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonCollectionRegion(mapCache, this, metadata, settings, properties, COLLECTION_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
|
||||
log.debug("Building query cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonQueryRegion(mapCache, this, properties, QUERY_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
|
||||
log.debug("Building timestamps cache region: " + regionName);
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, properties);
|
||||
return new RedissonTimestampsRegion(mapCache, this, properties, TIMESTAMPS_DEF);
|
||||
}
|
||||
|
||||
protected RMapCache<Object, Object> getCache(String regionName, Properties properties) {
|
||||
return redisson.getMapCache(regionName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonStrategyRegistrationProvider implements StrategyRegistrationProvider {
|
||||
|
||||
@Override
|
||||
public Iterable<StrategyRegistration> getStrategyRegistrations() {
|
||||
return Collections.<StrategyRegistration>singleton(new SimpleStrategyRegistrationImpl(
|
||||
RegionFactory.class,
|
||||
RedissonRegionFactory.class,
|
||||
"redisson",
|
||||
RedissonRegionFactory.class.getName(),
|
||||
RedissonRegionFactory.class.getSimpleName()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TransactionalDataRegion;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class BaseRegion implements TransactionalDataRegion, GeneralDataRegion {
|
||||
|
||||
RMapCache<Object, Object> mapCache;
|
||||
RegionFactory regionFactory;
|
||||
CacheDataDescription metadata;
|
||||
|
||||
int ttl;
|
||||
int maxIdle;
|
||||
|
||||
public BaseRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory, CacheDataDescription metadata, Properties properties, String defaultKey) {
|
||||
super();
|
||||
this.mapCache = mapCache;
|
||||
this.regionFactory = regionFactory;
|
||||
this.metadata = metadata;
|
||||
|
||||
String maxEntries = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_ENTRIES_SUFFIX);
|
||||
if (maxEntries != null) {
|
||||
mapCache.setMaxSize(Integer.valueOf(maxEntries));
|
||||
}
|
||||
String timeToLive = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.TTL_SUFFIX);
|
||||
if (timeToLive != null) {
|
||||
ttl = Integer.valueOf(timeToLive);
|
||||
}
|
||||
String maxIdleTime = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_IDLE_SUFFIX);
|
||||
if (maxIdleTime != null) {
|
||||
maxIdle = Integer.valueOf(maxIdleTime);
|
||||
}
|
||||
}
|
||||
|
||||
private String getProperty(Properties properties, String name, String defaultKey, String suffix) {
|
||||
String value = properties.getProperty(RedissonRegionFactory.CONFIG_PREFIX + name + suffix);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
String defValue = properties.getProperty(RedissonRegionFactory.CONFIG_PREFIX + defaultKey + suffix);
|
||||
if (defValue != null) {
|
||||
return defValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAware() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheDataDescription getCacheDataDescription() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mapCache.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws CacheException {
|
||||
try {
|
||||
mapCache.clear();
|
||||
mapCache.destroy();
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object key) {
|
||||
try {
|
||||
return mapCache.containsKey(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSizeInMemory() {
|
||||
return mapCache.sizeInMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getElementCountInMemory() {
|
||||
return mapCache.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getElementCountOnDisk() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, ?> toMap() {
|
||||
return Collections.unmodifiableMap(mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
return regionFactory.nextTimestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeout() {
|
||||
return (1 << 12) * 60000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
try {
|
||||
return mapCache.get(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
try {
|
||||
mapCache.fastPut(key, value, ttl, TimeUnit.MILLISECONDS, maxIdle, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
try {
|
||||
mapCache.fastRemove(key);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
try {
|
||||
mapCache.clear();
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteCollectionRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalCollectionRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonCollectionRegion extends BaseRegion implements CollectionRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonCollectionRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteCollectionRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalCollectionRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteEntityRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalEntityRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonEntityRegion extends BaseRegion implements EntityRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonEntityRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteEntityRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalEntityRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.CacheDataDescription;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.hibernate.strategy.NonStrictReadWriteNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadOnlyNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.ReadWriteNaturalIdRegionAccessStrategy;
|
||||
import org.redisson.hibernate.strategy.TransactionalNaturalIdRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonNaturalIdRegion extends BaseRegion implements NaturalIdRegion {
|
||||
|
||||
private Settings settings;
|
||||
|
||||
public RedissonNaturalIdRegion(RMapCache<Object, Object> mapCache, RegionFactory regionFactory,
|
||||
CacheDataDescription metadata, Settings settings, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, metadata, properties, defaultKey);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if (accessType == AccessType.READ_ONLY) {
|
||||
return new ReadOnlyNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.READ_WRITE) {
|
||||
return new ReadWriteNaturalIdRegionAccessStrategy(settings, this, mapCache);
|
||||
}
|
||||
if (accessType == AccessType.NONSTRICT_READ_WRITE) {
|
||||
return new NonStrictReadWriteNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
if (accessType == AccessType.TRANSACTIONAL) {
|
||||
return new TransactionalNaturalIdRegionAccessStrategy(settings, this);
|
||||
}
|
||||
|
||||
throw new CacheException("Unsupported access strategy: " + accessType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.spi.QueryResultsRegion;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonQueryRegion extends BaseRegion implements QueryResultsRegion {
|
||||
|
||||
public RedissonQueryRegion(RMapCache<Object, Object> mapCache,
|
||||
RegionFactory regionFactory, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, null, properties, defaultKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.region;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cache.spi.TimestampsRegion;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonTimestampsRegion extends BaseRegion implements TimestampsRegion {
|
||||
|
||||
public RedissonTimestampsRegion(RMapCache<Object, Object> mapCache,
|
||||
RegionFactory regionFactory, Properties properties, String defaultKey) {
|
||||
super(mapCache, regionFactory, null, properties, defaultKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,356 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.TransactionalDataRegion;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Strong Liu
|
||||
*
|
||||
*/
|
||||
public class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy {
|
||||
|
||||
private final UUID uuid = UUID.randomUUID();
|
||||
private final AtomicLong nextLockId = new AtomicLong();
|
||||
RMapCache<Object, Object> mapCache;
|
||||
|
||||
public AbstractReadWriteAccessStrategy(Settings settings, GeneralDataRegion region, RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region);
|
||||
this.mapCache = mapCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
RLock readLock = mapCache.getReadWriteLock(key).readLock();
|
||||
readLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
|
||||
if (item != null && item.isReadable(txTimestamp)) {
|
||||
return item.getValue();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
Comparator<Object> comparator = ((TransactionalDataRegion)region).getCacheDataDescription().getVersionComparator();
|
||||
boolean writeable = item == null || item.isWriteable(txTimestamp, version, comparator);
|
||||
if (writeable) {
|
||||
region.put(session, key, new Item(value, version, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
long timeout = region.nextTimestamp() + region.getTimeout();
|
||||
|
||||
Lock lock;
|
||||
if (item == null) {
|
||||
lock = new Lock(timeout, uuid, nextLockId.getAndIncrement(), version);
|
||||
} else {
|
||||
lock = item.lock(timeout, uuid, nextLockId.getAndIncrement());
|
||||
}
|
||||
region.put(session, key, lock);
|
||||
return lock;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
decrementLock(session, key, (Lock)item);
|
||||
} else {
|
||||
handleLockExpiry(session, key, item);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock and re-put the given key, lock combination.
|
||||
*/
|
||||
protected void decrementLock(SharedSessionContractImplementor session, Object key, Lock lock) {
|
||||
lock.unlock(region.nextTimestamp());
|
||||
region.put(session, key, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the timeout of a previous lock mapped to this key
|
||||
*/
|
||||
protected void handleLockExpiry(SharedSessionContractImplementor session, Object key, Lockable lock) {
|
||||
long ts = region.nextTimestamp() + region.getTimeout();
|
||||
// create new lock that times out immediately
|
||||
Lock newLock = new Lock(ts, uuid, nextLockId.getAndIncrement(), null);
|
||||
newLock.unlock(ts);
|
||||
region.put(session, key, newLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface type implemented by all wrapper objects in the cache.
|
||||
*/
|
||||
public interface Lockable {
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the enclosed value can be read by a transaction started at the given time.
|
||||
*/
|
||||
public boolean isReadable(long txTimestamp);
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the enclosed value can be replaced with one of the given version by a
|
||||
* transaction started at the given time.
|
||||
*/
|
||||
public boolean isWriteable(long txTimestamp, Object version, Comparator<Object> versionComparator);
|
||||
|
||||
/**
|
||||
* Returns the enclosed value.
|
||||
*/
|
||||
public Object getValue();
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the given lock can be unlocked using the given SoftLock instance as a handle.
|
||||
*/
|
||||
public boolean isUnlockable(SoftLock lock);
|
||||
|
||||
/**
|
||||
* Locks this entry, stamping it with the UUID and lockId given, with the lock timeout occuring at the specified
|
||||
* time. The returned Lock object can be used to unlock the entry in the future.
|
||||
*/
|
||||
public Lock lock(long timeout, UUID uuid, long lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper type representing unlocked items.
|
||||
*/
|
||||
public final static class Item implements Serializable, Lockable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Object value;
|
||||
private Object version;
|
||||
private long timestamp;
|
||||
|
||||
/**
|
||||
* Creates an unlocked item wrapping the given value with a version and creation timestamp.
|
||||
*/
|
||||
public Item(Object value, Object version, long timestamp) {
|
||||
this.value = value;
|
||||
this.version = version;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(long txTimestamp) {
|
||||
return txTimestamp > timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(long txTimestamp, Object newVersion, Comparator<Object> versionComparator) {
|
||||
return version != null && versionComparator.compare( version, newVersion ) < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnlockable(SoftLock lock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock lock(long timeout, UUID uuid, long lockId) {
|
||||
return new Lock(timeout, uuid, lockId, version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper type representing locked items.
|
||||
*/
|
||||
public final static class Lock implements Serializable, Lockable, SoftLock {
|
||||
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private UUID sourceUuid;
|
||||
private long lockId;
|
||||
private Object version;
|
||||
|
||||
private long timeout;
|
||||
private boolean concurrent;
|
||||
private int multiplicity = 1;
|
||||
private long unlockTimestamp;
|
||||
|
||||
/**
|
||||
* Creates a locked item with the given identifiers and object version.
|
||||
*/
|
||||
public Lock(long timeout, UUID sourceUuid, long lockId, Object version) {
|
||||
this.timeout = timeout;
|
||||
this.lockId = lockId;
|
||||
this.version = version;
|
||||
this.sourceUuid = sourceUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(long txTimestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(long txTimestamp, Object newVersion, Comparator versionComparator) {
|
||||
if ( txTimestamp > timeout ) {
|
||||
// if timedout then allow write
|
||||
return true;
|
||||
}
|
||||
if ( multiplicity > 0 ) {
|
||||
// if still locked then disallow write
|
||||
return false;
|
||||
}
|
||||
return version == null ? txTimestamp > unlockTimestamp : versionComparator.compare(
|
||||
version,
|
||||
newVersion
|
||||
) < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnlockable(SoftLock lock) {
|
||||
return equals( lock );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( o == this ) {
|
||||
return true;
|
||||
}
|
||||
else if ( o instanceof Lock ) {
|
||||
return ( lockId == ( (Lock) o ).lockId ) && sourceUuid.equals( ( (Lock) o ).sourceUuid );
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = ( sourceUuid != null ? sourceUuid.hashCode() : 0 );
|
||||
int temp = (int) lockId;
|
||||
for ( int i = 1; i < Long.SIZE / Integer.SIZE; i++ ) {
|
||||
temp ^= ( lockId >>> ( i * Integer.SIZE ) );
|
||||
}
|
||||
return hash + temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Lock has been concurrently locked by more than one transaction.
|
||||
*/
|
||||
public boolean wasLockedConcurrently() {
|
||||
return concurrent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock lock(long timeout, UUID uuid, long lockId) {
|
||||
concurrent = true;
|
||||
multiplicity++;
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks this Lock, and timestamps the unlock event.
|
||||
*/
|
||||
public void unlock(long timestamp) {
|
||||
if ( --multiplicity == 0 ) {
|
||||
unlockTimestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder( "Lock Source-UUID:" + sourceUuid + " Lock-ID:" + lockId );
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.RegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
abstract class BaseRegionAccessStrategy implements RegionAccessStrategy {
|
||||
|
||||
GeneralDataRegion region;
|
||||
Settings settings;
|
||||
|
||||
BaseRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
this.settings = settings;
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return putFromLoad(session, key, value, txTimestamp, version, settings.isMinimalPutsEnabled() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll() throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
region.evictAll();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory,
|
||||
String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetCollectionId( cacheKey );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
remove(session, key);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
unlockItem(session, key, lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetEntityId( cacheKey );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class NonStrictReadWriteNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public NonStrictReadWriteNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
remove(session, key);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) throws CacheException {
|
||||
unlockItem(session, key, lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadOnlyNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public ReadOnlyNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) throws CacheException {
|
||||
throw new UnsupportedOperationException("Unable to update read-only object");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadWriteCollectionRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public ReadWriteCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region,
|
||||
RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Strong Liu
|
||||
*
|
||||
*/
|
||||
public class ReadWriteEntityRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public ReadWriteEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region, RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
if (item == null) {
|
||||
region.put(session, key, new Item(value, version, region.nextTimestamp()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
Lock lockItem = (Lock) item;
|
||||
if (lockItem.wasLockedConcurrently()) {
|
||||
decrementLock(session, key, lockItem );
|
||||
return false;
|
||||
} else {
|
||||
region.put(session, key, new Item(value, currentVersion, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
handleLockExpiry(session, key, item );
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateEntityKey(id, persister, factory, tenantIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
* @author Eric Dalquist
|
||||
*
|
||||
*/
|
||||
public class ReadWriteNaturalIdRegionAccessStrategy extends AbstractReadWriteAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public ReadWriteNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region,
|
||||
RMapCache<Object, Object> mapCache) {
|
||||
super(settings, region, mapCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
if (item == null) {
|
||||
region.put(session, key, new Item(value, null, region.nextTimestamp()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) throws CacheException {
|
||||
RLock writeLock = mapCache.getReadWriteLock(key).writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
Lockable item = (Lockable) region.get(session, key);
|
||||
|
||||
if (item != null && item.isUnlockable(lock)) {
|
||||
Lock lockItem = (Lock) item;
|
||||
if (lockItem.wasLockedConcurrently()) {
|
||||
decrementLock(session, key, lockItem);
|
||||
return false;
|
||||
} else {
|
||||
region.put(session, key, new Item(value, null, region.nextTimestamp()));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
handleLockExpiry(session, key, item);
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.CollectionRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalCollectionRegionAccessStrategy extends BaseRegionAccessStrategy implements CollectionRegionAccessStrategy {
|
||||
|
||||
public TransactionalCollectionRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion getRegion() {
|
||||
return (CollectionRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.EntityRegion;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalEntityRegionAccessStrategy extends BaseRegionAccessStrategy implements EntityRegionAccessStrategy {
|
||||
|
||||
public TransactionalEntityRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion getRegion() {
|
||||
return (EntityRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
return insert(session, key, value, currentVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
return DefaultCacheKeysFactory.staticCreateEntityKey(id, persister, factory, tenantIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCacheKeyId(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate.strategy;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||
import org.hibernate.cache.spi.NaturalIdRegion;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
|
||||
|
||||
public TransactionalNaturalIdRegionAccessStrategy(Settings settings, GeneralDataRegion region) {
|
||||
super(settings, region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(SharedSessionContractImplementor session, Object key, long txTimestamp) throws CacheException {
|
||||
return region.get(session, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
if (minimalPutOverride && region.contains(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoftLock lockItem(SharedSessionContractImplementor session, Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockItem(SharedSessionContractImplementor session, Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdRegion getRegion() {
|
||||
return (NaturalIdRegion) region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SharedSessionContractImplementor session, Object key) throws CacheException {
|
||||
region.evict(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
region.put(session, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(SharedSessionContractImplementor session, Object key, Object value) throws CacheException {
|
||||
return insert(session, key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean afterUpdate(SharedSessionContractImplementor session, Object key, Object value, SoftLock lock) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
||||
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.redisson.hibernate.RedissonStrategyRegistrationProvider
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<blueprint default-activation="eager"
|
||||
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<bean id="strategyRegistrationProvider" class="org.redisson.hibernate.RedissonStrategyRegistrationProvider"/>
|
||||
|
||||
<service ref="strategyRegistrationProvider" interface="org.hibernate.boot.registry.selector.StrategyRegistrationProvider"/>
|
||||
|
||||
</blueprint>
|
@ -0,0 +1,84 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries(@NamedQuery(name = "testQuery", query = "from ItemReadWrite where name = :name"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||
@NaturalIdCache
|
||||
public class ItemReadWrite {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@NaturalId
|
||||
private String nid;
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(name = "Entries", joinColumns = @JoinColumn(name="Item_id"))
|
||||
@Column(name = "entry", nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item_entries")
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
|
||||
public ItemReadWrite() {
|
||||
}
|
||||
|
||||
public ItemReadWrite(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries(@NamedQuery(name = "testQuery", query = "from ItemTransactional where name = :name"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "item")
|
||||
@NaturalIdCache
|
||||
public class ItemTransactional {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@NaturalId
|
||||
private String nid;
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(name = "Entries", joinColumns = @JoinColumn(name="Item_id"))
|
||||
@Column(name = "entry", nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "item_entries")
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
|
||||
public ItemTransactional() {
|
||||
}
|
||||
|
||||
public ItemTransactional(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,236 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadWriteTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { ItemReadWrite.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
|
||||
cfg.setProperty("hibernate.cache.redisson.item.eviction.max_entries", "100");
|
||||
cfg.setProperty("hibernate.cache.redisson.item.expiration.time_to_live", "1500");
|
||||
cfg.setProperty("hibernate.cache.redisson.item.expiration.max_idle_time", "1000");
|
||||
|
||||
cfg.setProperty("hibernate.cache.redisson.item##NaturalId.eviction.max_entries", "1000");
|
||||
cfg.setProperty("hibernate.cache.redisson.item##NaturalId.expiration.time_to_live", "1100");
|
||||
cfg.setProperty("hibernate.cache.redisson.item##NaturalId.expiration.max_idle_time", "1200");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeToLive() throws InterruptedException {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Thread.sleep(900);
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(0, stats.getSecondLevelCacheStatistics("item").getMissCount());
|
||||
|
||||
Thread.sleep(600);
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getMissCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query = s.getNamedQuery("testQuery");
|
||||
query.setCacheable(true);
|
||||
query.setCacheRegion("myTestQuery");
|
||||
query.setParameter("name", "data");
|
||||
item = (ItemReadWrite) query.uniqueResult();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query2 = s.getNamedQuery("testQuery");
|
||||
query2.setCacheable(true);
|
||||
query2.setCacheRegion("myTestQuery");
|
||||
query2.setParameter("name", "data");
|
||||
item = (ItemReadWrite) query2.uniqueResult();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollection() {
|
||||
Long id = null;
|
||||
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
id = (Long) s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getHitCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalId() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.setNid("123");
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.bySimpleNaturalId(ItemReadWrite.class).load("123");
|
||||
assertThat(item).isNotNull();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getHitCount());
|
||||
|
||||
sessionFactory().getStatistics().logSummary();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithRefreshThenRollback() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
item.setName("newdata");
|
||||
s.update(item);
|
||||
s.flush();
|
||||
s.refresh(item);
|
||||
s.getTransaction().rollback();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemReadWrite) s.get(ItemReadWrite.class, id);
|
||||
Assert.assertEquals("data", item.getName());
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.redisson.hibernate.RedissonRegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { ItemTransactional.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictEntityRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query = s.getNamedQuery("testQuery");
|
||||
query.setCacheable(true);
|
||||
query.setCacheRegion("myTestQuery");
|
||||
query.setParameter("name", "data");
|
||||
item = (ItemTransactional) query.uniqueResult();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query2 = s.getNamedQuery("testQuery");
|
||||
query2.setCacheable(true);
|
||||
query2.setCacheRegion("myTestQuery");
|
||||
query2.setParameter("name", "data");
|
||||
item = (ItemTransactional) query2.uniqueResult();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("myTestQuery").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollection() {
|
||||
Long id = null;
|
||||
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
id = (Long) s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item_entries").getHitCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalId() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.setNid("123");
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.bySimpleNaturalId(ItemTransactional.class).load("123");
|
||||
assertThat(item).isNotNull();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdCacheStatistics("item##NaturalId").getHitCount());
|
||||
|
||||
sessionFactory().getStatistics().logSummary();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithRefreshThenRollback() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
item.setName("newdata");
|
||||
s.update(item);
|
||||
s.flush();
|
||||
s.refresh(item);
|
||||
s.getTransaction().rollback();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getSecondLevelCacheStatistics("item").getHitCount());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"singleServerConfig":{
|
||||
"address": "redis://127.0.0.1:6379"
|
||||
},
|
||||
"codec":{
|
||||
"class":"org.redisson.codec.FstCodec"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"singleServerConfig":{
|
||||
"address": "redis://127.0.0.1:6379"
|
||||
},
|
||||
"codec":{
|
||||
"class":"org.redisson.codec.FstCodec"
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-hibernate</artifactId>
|
||||
<version>2.14.2-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>redisson-hibernate-53</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Redisson/Hibernate-5.3.x+</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>de.ruedigermoeller</groupId>
|
||||
<artifactId>fst</artifactId>
|
||||
<version>2.54</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>5.3.7.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-testing</artifactId>
|
||||
<version>5.3.7.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<basedir>${basedir}</basedir>
|
||||
<header>${basedir}/../../header.txt</header>
|
||||
<quiet>false</quiet>
|
||||
<failIfMissing>true</failIfMissing>
|
||||
<aggregate>false</aggregate>
|
||||
<includes>
|
||||
<include>src/main/java/org/redisson/</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>target/**</exclude>
|
||||
</excludes>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<mapping>
|
||||
<java>JAVADOC_STYLE</java>
|
||||
</mapping>
|
||||
<strictCheck>true</strictCheck>
|
||||
<useDefaultMapping>true</useDefaultMapping>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.cfg.spi.DomainDataRegionBuildingContext;
|
||||
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
|
||||
import org.hibernate.cache.spi.DomainDataRegion;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.support.DomainDataRegionImpl;
|
||||
import org.hibernate.cache.spi.support.DomainDataStorageAccess;
|
||||
import org.hibernate.cache.spi.support.RegionFactoryTemplate;
|
||||
import org.hibernate.cache.spi.support.StorageAccess;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RScript;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.client.codec.LongCodec;
|
||||
import org.redisson.config.Config;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonRegionFactory extends RegionFactoryTemplate {
|
||||
|
||||
private static final Logger log = Logger.getLogger( RedissonRegionFactory.class );
|
||||
|
||||
private static final long serialVersionUID = 3785315696581773811L;
|
||||
|
||||
public static final String QUERY_DEF = "query";
|
||||
|
||||
public static final String COLLECTION_DEF = "collection";
|
||||
|
||||
public static final String ENTITY_DEF = "entity";
|
||||
|
||||
public static final String NATURAL_ID_DEF = "naturalid";
|
||||
|
||||
public static final String TIMESTAMPS_DEF = "timestamps";
|
||||
|
||||
public static final String MAX_ENTRIES_SUFFIX = ".eviction.max_entries";
|
||||
|
||||
public static final String TTL_SUFFIX = ".expiration.time_to_live";
|
||||
|
||||
public static final String MAX_IDLE_SUFFIX = ".expiration.max_idle_time";
|
||||
|
||||
public static final String CONFIG_PREFIX = "hibernate.cache.redisson.";
|
||||
|
||||
public static final String REDISSON_CONFIG_PATH = CONFIG_PREFIX + "config";
|
||||
|
||||
private RedissonClient redisson;
|
||||
|
||||
@Override
|
||||
protected void prepareForUse(SessionFactoryOptions settings, @SuppressWarnings("rawtypes") Map properties) throws CacheException {
|
||||
Config config = null;
|
||||
if (!properties.containsKey(REDISSON_CONFIG_PATH)) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.json");
|
||||
if (config == null) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.yaml");
|
||||
}
|
||||
} else {
|
||||
String configPath = ConfigurationHelper.getString(REDISSON_CONFIG_PATH, properties);
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), configPath);
|
||||
if (config == null) {
|
||||
config = loadConfig(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
throw new CacheException("Unable to locate Redisson configuration");
|
||||
}
|
||||
|
||||
this.redisson = Redisson.create(config);
|
||||
}
|
||||
|
||||
private Config loadConfig(String configPath) {
|
||||
try {
|
||||
return Config.fromJSON(new File(configPath));
|
||||
} catch (IOException e) {
|
||||
// trying next format
|
||||
try {
|
||||
return Config.fromYAML(new File(configPath));
|
||||
} catch (IOException e1) {
|
||||
throw new CacheException("Can't parse default yaml config", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Config loadConfig(ClassLoader classLoader, String fileName) {
|
||||
Config config = null;
|
||||
try {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
config = Config.fromJSON(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CacheException("Can't parse json config", e);
|
||||
}
|
||||
if (config == null) {
|
||||
try {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
config = Config.fromYAML(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CacheException("Can't parse yaml config", e);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseFromUse() {
|
||||
redisson.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimalPutsEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessType getDefaultAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
long time = System.currentTimeMillis() << 12;
|
||||
return redisson.getScript(LongCodec.INSTANCE).eval(RScript.Mode.READ_WRITE,
|
||||
"local currentTime = redis.call('get', KEYS[1]);"
|
||||
+ "if currentTime == false then "
|
||||
+ "redis.call('set', KEYS[1], ARGV[1]); "
|
||||
+ "return ARGV[1]; "
|
||||
+ "end;"
|
||||
+ "local nextValue = math.max(tonumber(ARGV[1]), tonumber(currentTime) + 1); "
|
||||
+ "redis.call('set', KEYS[1], nextValue); "
|
||||
+ "return nextValue;",
|
||||
RScript.ReturnType.INTEGER, Arrays.<Object>asList("redisson-hibernate-timestamp"), time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainDataRegion buildDomainDataRegion(
|
||||
DomainDataRegionConfig regionConfig,
|
||||
DomainDataRegionBuildingContext buildingContext) {
|
||||
verifyStarted();
|
||||
return new DomainDataRegionImpl(
|
||||
regionConfig,
|
||||
this,
|
||||
createDomainDataStorageAccess( regionConfig, buildingContext ),
|
||||
getImplicitCacheKeysFactory(),
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DomainDataStorageAccess createDomainDataStorageAccess(DomainDataRegionConfig regionConfig,
|
||||
DomainDataRegionBuildingContext buildingContext) {
|
||||
String defaultKey = null;
|
||||
if (!regionConfig.getCollectionCaching().isEmpty()) {
|
||||
defaultKey = COLLECTION_DEF;
|
||||
} else if (!regionConfig.getEntityCaching().isEmpty()) {
|
||||
defaultKey = ENTITY_DEF;
|
||||
} else if (!regionConfig.getNaturalIdCaching().isEmpty()) {
|
||||
defaultKey = NATURAL_ID_DEF;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to determine entity cache type!");
|
||||
}
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(regionConfig.getRegionName(), buildingContext.getSessionFactory().getProperties());
|
||||
return new RedissonStorage(mapCache, buildingContext.getSessionFactory().getProperties(), defaultKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StorageAccess createQueryResultsRegionStorageAccess(String regionName,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, sessionFactory.getProperties());
|
||||
return new RedissonStorage(mapCache, sessionFactory.getProperties(), QUERY_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StorageAccess createTimestampsRegionStorageAccess(String regionName,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
RMapCache<Object, Object> mapCache = getCache(regionName, sessionFactory.getProperties());
|
||||
return new RedissonStorage(mapCache, sessionFactory.getProperties(), TIMESTAMPS_DEF);
|
||||
}
|
||||
|
||||
protected RMapCache<Object, Object> getCache(String regionName, Map properties) {
|
||||
return redisson.getMapCache(regionName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.hibernate.cache.spi.support.DomainDataStorageAccess;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.redisson.api.RMapCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonStorage implements DomainDataStorageAccess {
|
||||
|
||||
private RMapCache<Object, Object> mapCache;
|
||||
|
||||
int ttl;
|
||||
int maxIdle;
|
||||
|
||||
public RedissonStorage(RMapCache<Object, Object> mapCache, Map<String, Object> properties, String defaultKey) {
|
||||
super();
|
||||
this.mapCache = mapCache;
|
||||
|
||||
String maxEntries = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_ENTRIES_SUFFIX);
|
||||
if (maxEntries != null) {
|
||||
mapCache.setMaxSize(Integer.valueOf(maxEntries));
|
||||
}
|
||||
String timeToLive = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.TTL_SUFFIX);
|
||||
if (timeToLive != null) {
|
||||
ttl = Integer.valueOf(timeToLive);
|
||||
}
|
||||
String maxIdleTime = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_IDLE_SUFFIX);
|
||||
if (maxIdleTime != null) {
|
||||
maxIdle = Integer.valueOf(maxIdleTime);
|
||||
}
|
||||
}
|
||||
|
||||
private String getProperty(Map<String, Object> properties, String name, String defaultKey, String suffix) {
|
||||
String maxEntries = (String) properties.get(RedissonRegionFactory.CONFIG_PREFIX + name + suffix);
|
||||
if (maxEntries != null) {
|
||||
return maxEntries;
|
||||
}
|
||||
String defValue = (String) properties.get(RedissonRegionFactory.CONFIG_PREFIX + defaultKey + suffix);
|
||||
if (defValue != null) {
|
||||
return defValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getFromCache(Object key, SharedSessionContractImplementor session) {
|
||||
return mapCache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putIntoCache(Object key, Object value, SharedSessionContractImplementor session) {
|
||||
mapCache.fastPut(key, value, ttl, TimeUnit.MILLISECONDS, maxIdle, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object key) {
|
||||
return mapCache.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictData() {
|
||||
mapCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictData(Object key) {
|
||||
mapCache.fastRemove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
mapCache.destroy();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright 2018 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonStrategyRegistrationProvider implements StrategyRegistrationProvider {
|
||||
|
||||
@Override
|
||||
public Iterable<StrategyRegistration> getStrategyRegistrations() {
|
||||
return Collections.<StrategyRegistration>singleton(new SimpleStrategyRegistrationImpl(
|
||||
RegionFactory.class,
|
||||
RedissonRegionFactory.class,
|
||||
"redisson",
|
||||
RedissonRegionFactory.class.getName(),
|
||||
RedissonRegionFactory.class.getSimpleName()));
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue