View Javadoc

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      // actually all we need would be a ConcurrentSet...
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         // all new keys added into the store are invisible
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                 // if the soft lock's element is null in the current transaction then the key is invisible
112                 invisibleKeys.add(softLock.getKey());
113             } else {
114                 // if the soft lock's element is not null in the current transaction then the key is visible
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 }