/hazelcast/src/main/java/com/hazelcast/impl/AbstractRecord.java

https://bitbucket.org/gabral6_gmailcom/hazelcast · Java · 490 lines · 382 code · 86 blank · 22 comment · 112 complexity · 83f6253d1ac3b5368d66057435db161c 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.impl;
  17. import com.hazelcast.impl.base.DistributedLock;
  18. import com.hazelcast.impl.base.ScheduledAction;
  19. import com.hazelcast.impl.concurrentmap.ValueHolder;
  20. import com.hazelcast.nio.Address;
  21. import com.hazelcast.nio.Data;
  22. import com.hazelcast.util.Clock;
  23. import java.util.*;
  24. import java.util.concurrent.ConcurrentHashMap;
  25. import static com.hazelcast.nio.IOUtil.toObject;
  26. @SuppressWarnings("VolatileLongOrDoubleField")
  27. public abstract class AbstractRecord extends AbstractSimpleRecord implements Record {
  28. protected volatile int hits = 0;
  29. protected volatile long version = 0;
  30. protected volatile long maxIdleMillis = Long.MAX_VALUE;
  31. protected volatile long writeTime = -1;
  32. protected volatile long removeTime = 0;
  33. protected volatile long lastAccessTime = 0;
  34. protected volatile long lastStoredTime = 0;
  35. protected volatile long creationTime = 0;
  36. protected volatile long expirationTime = Long.MAX_VALUE;
  37. protected volatile long lastUpdateTime = 0;
  38. protected volatile boolean dirty = false;
  39. protected volatile DistributedLock lock = null;
  40. protected volatile OptionalInfo optionalInfo = null;
  41. public AbstractRecord(CMap cmap, int blockId, Data key, long ttl, long maxIdleMillis, long id) {
  42. super(blockId, cmap, id, key);
  43. this.setCreationTime(Clock.currentTimeMillis());
  44. this.setTTL(ttl);
  45. this.maxIdleMillis = (maxIdleMillis == 0) ? Long.MAX_VALUE : maxIdleMillis;
  46. this.setVersion(0);
  47. }
  48. public void runBackupOps() {
  49. final Set<VersionedBackupOp> backupOps = getBackupOps();
  50. if (backupOps != null && !backupOps.isEmpty()) {
  51. Iterator<VersionedBackupOp> it = backupOps.iterator();
  52. while (it.hasNext()) {
  53. VersionedBackupOp bo = it.next();
  54. if (bo.getVersion() < getVersion() + 1) {
  55. it.remove();
  56. } else if (bo.getVersion() == getVersion() + 1) {
  57. bo.run();
  58. setVersion(bo.getVersion());
  59. it.remove();
  60. } else {
  61. return;
  62. }
  63. }
  64. }
  65. }
  66. public void addBackupOp(VersionedBackupOp bo) {
  67. if (getBackupOps() == null) {
  68. setBackupOps(new TreeSet<VersionedBackupOp>());
  69. }
  70. getBackupOps().add(bo);
  71. if (getBackupOps().size() > 4) {
  72. forceBackupOps();
  73. }
  74. }
  75. public void forceBackupOps() {
  76. if (getBackupOps() == null) return;
  77. Iterator<VersionedBackupOp> it = getBackupOps().iterator();
  78. while (it.hasNext()) {
  79. VersionedBackupOp v = it.next();
  80. v.run();
  81. setVersion(v.getVersion());
  82. it.remove();
  83. }
  84. }
  85. public Object getKey() {
  86. return toObject(key);
  87. }
  88. public Long[] getIndexes() {
  89. if (optionalInfo == null) return null;
  90. return getOptionalInfo().indexes;
  91. }
  92. public byte[] getIndexTypes() {
  93. if (optionalInfo == null) return null;
  94. return getOptionalInfo().indexTypes;
  95. }
  96. public void setIndexes(Long[] indexes, byte[] indexTypes) {
  97. if (indexes != null) {
  98. this.getOptionalInfo().indexes = indexes;
  99. this.getOptionalInfo().indexTypes = indexTypes;
  100. }
  101. }
  102. // called from ServiceThread
  103. public boolean lock(int threadId, Address address) {
  104. invalidateValueCache();
  105. final DistributedLock dl = lock;
  106. if (dl == null) {
  107. lock = new DistributedLock(address, threadId);
  108. return true;
  109. }
  110. if (dl.lock(address, threadId)) {
  111. lock = dl;
  112. return true;
  113. }
  114. return false;
  115. }
  116. // called from ServiceThread
  117. public boolean unlock(int threadId, Address address) {
  118. invalidateValueCache();
  119. final DistributedLock dl = lock;
  120. return dl == null || dl.unlock(address, threadId);
  121. }
  122. public boolean testLock(int threadId, Address address) {
  123. final DistributedLock dl = lock;
  124. return dl == null || dl.testLock(threadId, address);
  125. }
  126. public DistributedLock getLock() {
  127. return lock;
  128. }
  129. public void setLock(DistributedLock lock) {
  130. this.lock = lock;
  131. }
  132. public boolean isLocked() {
  133. final DistributedLock dl = lock;
  134. return dl != null && dl.isLocked();
  135. }
  136. public int getLockCount() {
  137. final DistributedLock dl = lock;
  138. return (dl == null) ? 0 : dl.getLockCount();
  139. }
  140. // called from ServiceThread
  141. public void clearLock() {
  142. lock = null;
  143. }
  144. public Address getLockAddress() {
  145. final DistributedLock dl = lock;
  146. return (dl == null) ? null : dl.getLockAddress();
  147. }
  148. public long getLockAcquireTime() {
  149. final DistributedLock dl = lock;
  150. return (dl != null ? dl.getAcquireTime() : -1L);
  151. }
  152. protected void invalidateValueCache() {
  153. }
  154. public void addScheduledAction(ScheduledAction scheduledAction) {
  155. if (getScheduledActions() == null) {
  156. setScheduledActions(new LinkedList<ScheduledAction>());
  157. }
  158. getScheduledActions().add(scheduledAction);
  159. }
  160. public boolean isRemovable() {
  161. return !isActive() && valueCount() <= 0 && getLockCount() <= 0 && !hasListener()
  162. && getScheduledActionCount() == 0 && getBackupOpCount() == 0;
  163. }
  164. public boolean isEvictable() {
  165. return getLockCount() <= 0 && !hasListener() && getScheduledActionCount() == 0;
  166. }
  167. public boolean hasListener() {
  168. return getListeners() != null && getListeners().size() > 0;
  169. }
  170. public void addListener(Address address, boolean returnValue) {
  171. if (getListeners() == null) {
  172. setMapListeners(new ConcurrentHashMap<Address, Boolean>(1));
  173. }
  174. getListeners().put(address, returnValue);
  175. }
  176. public void removeListener(Address address) {
  177. if (getListeners() == null) {
  178. return;
  179. }
  180. getListeners().remove(address);
  181. }
  182. public void setLastUpdated() {
  183. if (expirationTime != Long.MAX_VALUE && expirationTime > 0) {
  184. long ttl = expirationTime - (lastUpdateTime > 0L ? lastUpdateTime : creationTime);
  185. setTTL(ttl);
  186. }
  187. setLastUpdateTime(Clock.currentTimeMillis());
  188. }
  189. public void setLastAccessed() {
  190. setLastAccessTime(Clock.currentTimeMillis());
  191. incrementHits();
  192. }
  193. public long getExpirationTime() {
  194. return expirationTime;
  195. }
  196. public long getRemainingTTL() {
  197. if (expirationTime == Long.MAX_VALUE) {
  198. return Long.MAX_VALUE;
  199. } else {
  200. long ttl = expirationTime - Clock.currentTimeMillis();
  201. return (ttl < 0) ? 1 : ttl;
  202. }
  203. }
  204. public long getRemainingIdle() {
  205. if (maxIdleMillis == Long.MAX_VALUE) {
  206. return Long.MAX_VALUE;
  207. } else {
  208. long lastTouch = Math.max(lastAccessTime, creationTime);
  209. long idle = Clock.currentTimeMillis() - lastTouch;
  210. return maxIdleMillis - idle;
  211. }
  212. }
  213. public void setMaxIdle(long idle) {
  214. if (idle <= 0 || idle == Long.MAX_VALUE) {
  215. maxIdleMillis = Long.MAX_VALUE;
  216. } else {
  217. maxIdleMillis = idle;
  218. }
  219. }
  220. public void setExpirationTime(final long expTime) {
  221. if (expTime <= 0) {
  222. this.expirationTime = Long.MAX_VALUE;
  223. } else {
  224. this.expirationTime = expTime;
  225. }
  226. }
  227. public void setTTL(long ttl) {
  228. if (ttl <= 0 || ttl == Long.MAX_VALUE) {
  229. setExpirationTime(Long.MAX_VALUE);
  230. } else {
  231. setExpirationTime(Clock.currentTimeMillis() + ttl);
  232. }
  233. }
  234. public void setInvalid() {
  235. expirationTime = (Clock.currentTimeMillis() - 10);
  236. }
  237. public boolean isValid(long now) {
  238. if (expirationTime == Long.MAX_VALUE && maxIdleMillis == Long.MAX_VALUE) {
  239. return true;
  240. }
  241. long lastTouch = Math.max(lastUpdateTime, Math.max(lastAccessTime, creationTime));
  242. long idle = now - lastTouch;
  243. return expirationTime > now && (maxIdleMillis > idle);
  244. }
  245. public boolean isValid() {
  246. return active && isValid(Clock.currentTimeMillis());
  247. }
  248. public void markRemoved() {
  249. setActive(false);
  250. setRemoveTime(Clock.currentTimeMillis());
  251. }
  252. public void setActive() {
  253. setRemoveTime(0);
  254. setActive(true);
  255. }
  256. public long getVersion() {
  257. return version;
  258. }
  259. public void setVersion(long version) {
  260. this.version = version;
  261. }
  262. public void incrementVersion() {
  263. this.version++;
  264. }
  265. public long getCreationTime() {
  266. return creationTime;
  267. }
  268. public void setCreationTime(long newValue) {
  269. creationTime = newValue;
  270. }
  271. public long getLastAccessTime() {
  272. return lastAccessTime;
  273. }
  274. public void setLastAccessTime(long lastAccessTime) {
  275. this.lastAccessTime = lastAccessTime;
  276. }
  277. public long getLastUpdateTime() {
  278. return lastUpdateTime;
  279. }
  280. public void setLastUpdateTime(long lastUpdateTime) {
  281. this.lastUpdateTime = lastUpdateTime;
  282. }
  283. public int getHits() {
  284. return hits;
  285. }
  286. public void incrementHits() {
  287. hits++;
  288. }
  289. public void setActive(boolean active) {
  290. this.active = active;
  291. invalidateValueCache();
  292. }
  293. public Collection<ValueHolder> getMultiValues() {
  294. if (optionalInfo == null) return null;
  295. return getOptionalInfo().lsMultiValues;
  296. }
  297. public void setMultiValues(Collection<ValueHolder> lsValues) {
  298. if (lsValues != null || optionalInfo != null) {
  299. this.getOptionalInfo().lsMultiValues = lsValues;
  300. }
  301. }
  302. public int getBackupOpCount() {
  303. if (optionalInfo == null) return 0;
  304. return (getOptionalInfo().backupOps == null) ? 0 : getOptionalInfo().backupOps.size();
  305. }
  306. public SortedSet<VersionedBackupOp> getBackupOps() {
  307. return getOptionalInfo().backupOps;
  308. }
  309. public void setBackupOps(SortedSet<VersionedBackupOp> backupOps) {
  310. if (backupOps != null) {
  311. this.getOptionalInfo().backupOps = backupOps;
  312. }
  313. }
  314. public boolean isDirty() {
  315. return dirty;
  316. }
  317. public void setDirty(boolean dirty) {
  318. this.dirty = dirty;
  319. }
  320. public long getWriteTime() {
  321. return writeTime;
  322. }
  323. public void setWriteTime(long writeTime) {
  324. this.writeTime = writeTime;
  325. }
  326. public long getRemoveTime() {
  327. return removeTime;
  328. }
  329. public void setRemoveTime(long removeTime) {
  330. this.removeTime = removeTime;
  331. }
  332. public boolean hasScheduledAction() {
  333. return optionalInfo != null && optionalInfo.lsScheduledActions != null &&
  334. optionalInfo.lsScheduledActions.size() > 0;
  335. }
  336. public List<ScheduledAction> getScheduledActions() {
  337. if (optionalInfo == null) return null;
  338. return getOptionalInfo().lsScheduledActions;
  339. }
  340. public void setScheduledActions(List<ScheduledAction> lsScheduledActions) {
  341. if (lsScheduledActions != null) {
  342. this.getOptionalInfo().lsScheduledActions = lsScheduledActions;
  343. }
  344. }
  345. public Map<Address, Boolean> getListeners() {
  346. if (optionalInfo == null) return null;
  347. return getOptionalInfo().mapListeners;
  348. }
  349. public void setMapListeners(Map<Address, Boolean> mapListeners) {
  350. if (mapListeners != null) {
  351. this.getOptionalInfo().mapListeners = mapListeners;
  352. }
  353. }
  354. public int getScheduledActionCount() {
  355. if (optionalInfo == null) return 0;
  356. return (getOptionalInfo().lsScheduledActions == null) ? 0 : getOptionalInfo().lsScheduledActions.size();
  357. }
  358. public OptionalInfo getOptionalInfo() {
  359. if (optionalInfo == null) {
  360. optionalInfo = new OptionalInfo();
  361. }
  362. return optionalInfo;
  363. }
  364. public void setLastStoredTime(long lastStoredTime) {
  365. this.lastStoredTime = lastStoredTime;
  366. }
  367. public long getLastStoredTime() {
  368. return lastStoredTime;
  369. }
  370. public boolean isRemoved() {
  371. return !active && removeTime > 0;
  372. }
  373. /**
  374. * True if record is not removed (map.remove() ...)
  375. * and either is not active or not valid or has not value (may because of locking)
  376. */
  377. public boolean isLoadable() {
  378. return !isRemoved() && (!isActive() || !isValid() || !hasValueData());
  379. }
  380. public int hashCode() {
  381. return super.hashCode();
  382. }
  383. public boolean equals(Object o) {
  384. if (this == o) return true;
  385. if (!(o instanceof AbstractRecord)) return false;
  386. Record record = (Record) o;
  387. return record.getId() == getId();
  388. }
  389. public String toString() {
  390. return "Record key=" + getKeyData() + ", active=" + isActive()
  391. + ", version=" + getVersion() + ", removable=" + isRemovable()
  392. + ", evictable=" + isEvictable() + ", valueCount= " + valueCount()
  393. + ", isLocked= " + isLocked() + ", scheduled= " + getScheduledActionCount()
  394. ;
  395. }
  396. class OptionalInfo {
  397. volatile Collection<ValueHolder> lsMultiValues = null; // multimap values
  398. Long[] indexes; // indexes of the current value;
  399. byte[] indexTypes; // index types of the current value;
  400. List<ScheduledAction> lsScheduledActions = null;
  401. SortedSet<VersionedBackupOp> backupOps = null;
  402. Map<Address, Boolean> mapListeners = null;
  403. }
  404. }