1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
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 net.sf.ehcache.transaction;
17
18 import net.sf.ehcache.Element;
19 import net.sf.ehcache.store.chm.ConcurrentHashMap;
20 import net.sf.ehcache.transaction.local.LocalTransactionContext;
21
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentMap;
26
27 /***
28 * A SoftLockFactory implementation which creates soft locks with Read-Committed isolation level
29 *
30 * @author Ludovic Orban
31 */
32 public class ReadCommittedSoftLockFactoryImpl implements SoftLockFactory {
33
34 private static final Object MARKER = new Object();
35
36 private final String cacheManagerName;
37 private final String cacheName;
38
39
40 private final ConcurrentMap<ReadCommittedSoftLockImpl, Object> newKeyLocks = new ConcurrentHashMap<ReadCommittedSoftLockImpl, Object>();
41
42 private final ConcurrentMap<ReadCommittedSoftLockImpl, Object> allLocks = new ConcurrentHashMap<ReadCommittedSoftLockImpl, Object>();
43
44 /***
45 * Create a new ReadCommittedSoftLockFactoryImpl instance for a cache
46 * @param cacheManagerName the name of the cache manager
47 * @param cacheName the name of the cache
48 */
49 public ReadCommittedSoftLockFactoryImpl(String cacheManagerName, String cacheName) {
50 this.cacheManagerName = cacheManagerName;
51 this.cacheName = cacheName;
52 }
53
54 /***
55 * Get the cache manager name
56 * @return the cache manager name
57 */
58 String getCacheManagerName() {
59 return cacheManagerName;
60 }
61
62 /***
63 * Get the cache name
64 * @return the cache name
65 */
66 String getCacheName() {
67 return cacheName;
68 }
69
70 /***
71 * {@inheritDoc}
72 */
73 public SoftLock createSoftLock(TransactionID transactionID, Object key, Element newElement, Element oldElement) {
74 ReadCommittedSoftLockImpl softLock = new ReadCommittedSoftLockImpl(this, transactionID, key, newElement, oldElement);
75
76 allLocks.put(softLock, MARKER);
77
78 if (oldElement == null) {
79 newKeyLocks.put(softLock, MARKER);
80 }
81 return softLock;
82 }
83
84 /***
85 * Get a lock
86 * @param transactionId the lock transaction ID
87 * @param key the lock key
88 * @return the lock, or null if there is no lock created with this transaction ID and key
89 */
90 ReadCommittedSoftLockImpl getLock(TransactionID transactionId, Object key) {
91 for (ReadCommittedSoftLockImpl readCommittedSoftLock : allLocks.keySet()) {
92 if (readCommittedSoftLock.getTransactionID().equals(transactionId) && readCommittedSoftLock.getKey().equals(key)) {
93 return readCommittedSoftLock;
94 }
95 }
96 return null;
97 }
98
99 /***
100 * {@inheritDoc}
101 */
102 public Set<Object> getKeysInvisibleInContext(LocalTransactionContext currentTransactionContext) {
103 Set<Object> invisibleKeys = new HashSet<Object>();
104
105
106 invisibleKeys.addAll(getNewKeys());
107
108 List<SoftLock> currentTransactionContextSoftLocks = currentTransactionContext.getSoftLocksForCache(cacheName);
109 for (SoftLock softLock : currentTransactionContextSoftLocks) {
110 if (softLock.getElement(currentTransactionContext.getTransactionId()) == null) {
111
112 invisibleKeys.add(softLock.getKey());
113 } else {
114
115 invisibleKeys.remove(softLock.getKey());
116 }
117 }
118
119 return invisibleKeys;
120 }
121
122 /***
123 * {@inheritDoc}
124 */
125 public Set<TransactionID> collectExpiredTransactionIDs() {
126 Set<TransactionID> result = new HashSet<TransactionID>();
127
128 for (ReadCommittedSoftLockImpl softLock : allLocks.keySet()) {
129 if (softLock.isExpired()) {
130 result.add(softLock.getTransactionID());
131 }
132 }
133
134 return result;
135 }
136
137 /***
138 * {@inheritDoc}
139 */
140 public Set<SoftLock> collectAllSoftLocksForTransactionID(TransactionID transactionID) {
141 Set<SoftLock> result = new HashSet<SoftLock>();
142
143 for (ReadCommittedSoftLockImpl softLock : allLocks.keySet()) {
144 if (softLock.getTransactionID().equals(transactionID)) {
145 result.add(softLock);
146 }
147 }
148
149 return result;
150 }
151
152 /***
153 * Callback when a soft lock died
154 * @param softLock the soft lock which died
155 */
156 void clearSoftLock(ReadCommittedSoftLockImpl softLock) {
157 newKeyLocks.remove(softLock);
158
159 allLocks.remove(softLock);
160 }
161
162 private Set<Object> getNewKeys() {
163 Set<Object> result = new HashSet<Object>();
164
165 for (ReadCommittedSoftLockImpl softLock : newKeyLocks.keySet()) {
166 result.add(softLock.getKey());
167 }
168
169 return result;
170 }
171
172 }