/hazelcast-hibernate/src/main/java/com/hazelcast/hibernate/local/LocalRegionCache.java

https://bitbucket.org/gabral6_gmailcom/hazelcast · Java · 250 lines · 203 code · 29 blank · 18 comment · 66 complexity · a5fc53a3872027e207f0ec56d69f6f53 MD5 · raw file

  1. /*
  2. * Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.hazelcast.hibernate.local;
  17. import com.hazelcast.config.MapConfig;
  18. import com.hazelcast.core.HazelcastInstance;
  19. import com.hazelcast.core.ITopic;
  20. import com.hazelcast.core.Message;
  21. import com.hazelcast.core.MessageListener;
  22. import com.hazelcast.hibernate.CacheEnvironment;
  23. import com.hazelcast.hibernate.RegionCache;
  24. import com.hazelcast.util.Clock;
  25. import org.hibernate.cache.CacheDataDescription;
  26. import org.hibernate.cache.access.SoftLock;
  27. import java.util.*;
  28. import java.util.Map.Entry;
  29. import java.util.concurrent.ConcurrentHashMap;
  30. import java.util.concurrent.ConcurrentMap;
  31. /**
  32. * @mdogan 11/9/12
  33. */
  34. public class LocalRegionCache implements RegionCache {
  35. protected final ITopic<Object> topic;
  36. protected final MessageListener<Object> messageListener;
  37. protected final ConcurrentMap<Object, Value> cache;
  38. protected final Comparator versionComparator;
  39. protected MapConfig config;
  40. public LocalRegionCache(final String name, final HazelcastInstance hazelcastInstance,
  41. final CacheDataDescription metadata) {
  42. try {
  43. config = hazelcastInstance != null ? hazelcastInstance.getConfig().findMatchingMapConfig(name) : null;
  44. } catch (UnsupportedOperationException ignored) {
  45. }
  46. versionComparator = metadata != null && metadata.isVersioned() ? metadata.getVersionComparator() : null;
  47. cache = new ConcurrentHashMap<Object, Value>();
  48. messageListener = createMessageListener();
  49. if (hazelcastInstance != null) {
  50. topic = hazelcastInstance.getTopic(name);
  51. topic.addMessageListener(messageListener);
  52. } else {
  53. topic = null;
  54. }
  55. }
  56. public Object get(final Object key) {
  57. final Value value = cache.get(key);
  58. return value != null ? value.getValue() : null;
  59. }
  60. public boolean put(final Object key, final Object value, final Object currentVersion) {
  61. final Value newValue = new Value(currentVersion, value, null, Clock.currentTimeMillis());
  62. cache.put(key, newValue);
  63. return true;
  64. }
  65. public boolean update(final Object key, final Object value, final Object currentVersion,
  66. final Object previousVersion, final SoftLock lock) {
  67. if (lock == LOCK_FAILURE) {
  68. return false;
  69. }
  70. final Value currentValue = cache.get(key);
  71. if (lock == LOCK_SUCCESS) {
  72. if (currentValue != null && currentVersion != null
  73. && versionComparator.compare(currentVersion, currentValue.getVersion()) < 0) {
  74. return false;
  75. }
  76. }
  77. if (topic != null) {
  78. topic.publish(createMessage(key, value, currentVersion));
  79. }
  80. cache.put(key, new Value(currentVersion, value, lock, Clock.currentTimeMillis()));
  81. return true;
  82. }
  83. protected Object createMessage(final Object key, Object value, final Object currentVersion) {
  84. return new Invalidation(key, currentVersion);
  85. }
  86. protected MessageListener<Object> createMessageListener() {
  87. return new MessageListener<Object>() {
  88. public void onMessage(final Message<Object> message) {
  89. final Invalidation invalidation = (Invalidation) message.getMessageObject();
  90. if (versionComparator != null) {
  91. final Value value = cache.get(invalidation.getKey());
  92. if (value != null) {
  93. Object currentVersion = value.getVersion();
  94. Object newVersion = invalidation.getVersion();
  95. if (versionComparator.compare(newVersion, currentVersion) > 0) {
  96. cache.remove(invalidation.getKey(), value);
  97. }
  98. }
  99. } else {
  100. cache.remove(invalidation.getKey());
  101. }
  102. }
  103. };
  104. }
  105. public boolean remove(final Object key) {
  106. return cache.remove(key) != null;
  107. }
  108. public SoftLock tryLock(final Object key, final Object version) {
  109. final Value value = cache.get(key);
  110. if (value == null) {
  111. if (cache.putIfAbsent(key, new Value(version, null, LOCK_SUCCESS, Clock.currentTimeMillis())) == null) {
  112. return LOCK_SUCCESS;
  113. } else {
  114. return LOCK_FAILURE;
  115. }
  116. } else {
  117. if (version == null || versionComparator.compare(version, value.getVersion()) >= 0) {
  118. if (cache.replace(key, value, value.createLockedValue(LOCK_SUCCESS))) {
  119. return LOCK_SUCCESS;
  120. } else {
  121. return LOCK_FAILURE;
  122. }
  123. } else {
  124. return LOCK_FAILURE;
  125. }
  126. }
  127. }
  128. public void unlock(final Object key, SoftLock lock) {
  129. final Value value = cache.get(key);
  130. if (value != null) {
  131. final SoftLock currentLock = value.getLock();
  132. if (currentLock == lock) {
  133. cache.replace(key, value, value.createUnlockedValue());
  134. }
  135. }
  136. }
  137. public boolean contains(final Object key) {
  138. return cache.containsKey(key);
  139. }
  140. public void clear() {
  141. cache.clear();
  142. }
  143. public long size() {
  144. return cache.size();
  145. }
  146. public long getSizeInMemory() {
  147. return 0;
  148. }
  149. public Map asMap() {
  150. return cache;
  151. }
  152. void cleanup() {
  153. final int maxSize;
  154. final long timeToLive;
  155. if (config != null) {
  156. maxSize = config.getMaxSizeConfig().getSize();
  157. timeToLive = config.getTimeToLiveSeconds() * 1000L;
  158. } else {
  159. maxSize = 100000;
  160. timeToLive = CacheEnvironment.getDefaultCacheTimeoutInMillis();
  161. }
  162. if ((maxSize > 0 && maxSize != Integer.MAX_VALUE) || timeToLive > 0) {
  163. final Iterator<Entry<Object, Value>> iter = cache.entrySet().iterator();
  164. SortedSet<EvictionEntry> entries = null;
  165. final long now = Clock.currentTimeMillis();
  166. while (iter.hasNext()) {
  167. final Entry<Object, Value> e = iter.next();
  168. final Object k = e.getKey();
  169. final Value v = e.getValue();
  170. if (v.getLock() == LOCK_SUCCESS) {
  171. continue;
  172. }
  173. if (v.getCreationTime() + timeToLive > now) {
  174. iter.remove();
  175. } else if (maxSize > 0 && maxSize != Integer.MAX_VALUE) {
  176. if (entries == null) {
  177. entries = new TreeSet<EvictionEntry>();
  178. }
  179. entries.add(new EvictionEntry(k, v));
  180. }
  181. }
  182. final int diff = cache.size() - maxSize;
  183. final int k = diff >= 0 ? (diff + maxSize * 20 / 100) : 0;
  184. if (k > 0 && entries != null) {
  185. int i = 0;
  186. for (EvictionEntry entry : entries) {
  187. if (cache.remove(entry.key, entry.value)) {
  188. if (++i == k) {
  189. break;
  190. }
  191. }
  192. }
  193. }
  194. }
  195. }
  196. private class EvictionEntry implements Comparable<EvictionEntry> {
  197. final Object key;
  198. final Value value;
  199. private EvictionEntry(final Object key, final Value value) {
  200. this.key = key;
  201. this.value = value;
  202. }
  203. public int compareTo(final EvictionEntry o) {
  204. final long thisVal = this.value.getCreationTime();
  205. final long anotherVal = o.value.getCreationTime();
  206. return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));
  207. }
  208. }
  209. private static final SoftLock LOCK_SUCCESS = new SoftLock() {
  210. @Override
  211. public String toString() {
  212. return "Lock::Success";
  213. }
  214. };
  215. private static final SoftLock LOCK_FAILURE = new SoftLock() {
  216. @Override
  217. public String toString() {
  218. return "Lock::Failure";
  219. }
  220. };
  221. }