001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package java.util.concurrent;
005:
006: import com.tc.object.TCObject;
007: import com.tc.object.bytecode.Clearable;
008: import com.tc.object.bytecode.Manageable;
009: import com.tc.object.bytecode.ManagerUtil;
010: import com.tc.object.bytecode.TCMap;
011: import com.tc.object.bytecode.TCMapEntry;
012: import com.tcclient.util.ConcurrentHashMapEntrySetWrapper;
013:
014: import java.util.ArrayList;
015: import java.util.Arrays;
016: import java.util.Collection;
017: import java.util.Collections;
018: import java.util.Iterator;
019: import java.util.Map;
020: import java.util.Set;
021:
022: @SuppressWarnings("unchecked")
023: /**
024: * Note that not all the methods of TCMap are implemented here.
025: *
026: * The ones that can't be found in this class are implemented through
027: * byte-code instrumentation, by adapting or renaming the original put and
028: * remove methods. This is done in the JavaUtilConcurrentHashMapAdapter class.
029: */
030: public abstract class ConcurrentHashMapTC extends ConcurrentHashMap
031: implements TCMap, Clearable, Manageable {
032: private boolean evictionEnabled = true;
033:
034: // These abstract methods are merely here so that they can be referenced by
035: // the code in this class. When the ConcurrentHashMapTC is merged into
036: // ConcurrentHashMap class, these abstract methods are simply ignored. They
037: // are implemented during the actual instrumentation of ConcurrentHashMap.
038: abstract void __tc_fullyReadLock();
039:
040: abstract void __tc_fullyReadUnlock();
041:
042: /*
043: * ConcurrentHashMap uses the hashcode of the key and identify the segment to use. Each segment is an ReentrantLock.
044: * This prevents multiple threads to update the same segment at the same time. To support in DSO, we need to check if
045: * the ConcurrentHashMap is a shared object. If it is, we check if the hashcode of the key is the same as the
046: * System.identityHashCode. If it is, we will use the DSO ObjectID of the key to be the hashcode. Since the ObjectID
047: * of the key is a cluster-wide constant, different node will identify the same segment based on the ObjectID of the
048: * key. If the hashcode of the key is not the same as the System.identityHashCode, that would mean the application has
049: * defined the hashcode of the key and in this case, we could use honor the application defined hashcode of the key.
050: * The reason that we do not want to always use the ObjectID of the key is because if the application has defined the
051: * hashcode of the key, map.get(key1) and map.get(key2) will return the same object if key1 and key2 has the same
052: * application defined hashcode even though key1 and key2 has 2 different ObjectID. Using ObjectID as the hashcode in
053: * this case will prevent map.get(key1) and map.get(key2) to return the same result. If the application has not
054: * defined the hashcode of the key, key1 and key2 will have 2 different hashcode (due to the fact that they will have
055: * different System.identityHashCode). Therefore, map.get(key1) and map.get(key2) will return different objects. In
056: * this case, using ObjectID will have the proper behavior. One limitation is that if the application define the
057: * hashcode as some combination of system specific data such as a combination of System.identityHashCode() and some
058: * other data, the current support of ConcurrentHashMap does not support this scenario. Another limitation is that if
059: * the application defined hashcode of the key happens to be the same as the System.identityHashCode, the current
060: * support of ConcurrentHashMap does not support this scenario either.
061: */
062: private int __tc_hash(Object obj) {
063: return __tc_hash(obj, true);
064: }
065:
066: private int __tc_hash(Object obj, boolean flag) {
067: int i = obj.hashCode();
068: boolean useObjectIDHashCode = false;
069:
070: if (System.identityHashCode(obj) == i) {
071: if (flag) {
072: if (__tc_managed() != null
073: || ManagerUtil.isCreationInProgress())
074: useObjectIDHashCode = true;
075: } else {
076: useObjectIDHashCode = true;
077: }
078: }
079:
080: if (useObjectIDHashCode) {
081: TCObject tcobject = ManagerUtil.shareObjectIfNecessary(obj);
082: if (tcobject != null) {
083: i = tcobject.getObjectID().hashCode();
084: }
085: }
086:
087: i += ~(i << 9);
088: i ^= i >>> 14;
089: i += i << 4;
090: i ^= i >>> 10;
091:
092: return i;
093: }
094:
095: private boolean __tc_isDsoHashRequired(Object obj) {
096: ManagerUtil.lookupExistingOrNull(obj);
097: return __tc_managed() == null
098: || ManagerUtil.lookupExistingOrNull(obj) != null
099: || obj.hashCode() != System.identityHashCode(obj);
100: }
101:
102: /*
103: * Provides access to the real entryset that is wrapped by the
104: * ConcurrentHashMapEntrySetWrapper.
105: */
106: public Set __tc_delegateEntrySet() {
107: Set set = entrySet();
108: if (set instanceof ConcurrentHashMapEntrySetWrapper) {
109: return ((ConcurrentHashMapEntrySetWrapper) set)
110: .getDelegateEntrySet();
111: } else {
112: return set;
113: }
114: }
115:
116: /*
117: * CHM-wide locking methods
118: */
119: private void __tc_fullyWriteLock() {
120: for (int i = 0; i < segments.length; i++) {
121: segments[i].lock();
122: }
123: }
124:
125: private void __tc_fullyWriteUnlock() {
126: for (int i = 0; i < segments.length; i++) {
127: segments[i].unlock();
128: }
129: }
130:
131: /*
132: * TCMap methods
133: */
134: public Collection __tc_getAllEntriesSnapshot() {
135: if (__tc_isManaged()) {
136: try {
137: __tc_fullyReadLock();
138: return __tc_getAllEntriesSnapshotInternal();
139: } finally {
140: __tc_fullyReadUnlock();
141: }
142: } else {
143: return __tc_getAllEntriesSnapshotInternal();
144: }
145: }
146:
147: public synchronized Collection __tc_getAllEntriesSnapshotInternal() {
148: return new ArrayList(entrySet());
149: }
150:
151: public Collection __tc_getAllLocalEntriesSnapshot() {
152: if (__tc_isManaged()) {
153: try {
154: __tc_fullyReadLock();
155: return __tc_getAllLocalEntriesSnapshotInternal();
156: } finally {
157: __tc_fullyReadUnlock();
158: }
159: } else {
160: return __tc_getAllLocalEntriesSnapshotInternal();
161: }
162: }
163:
164: private Collection __tc_getAllLocalEntriesSnapshotInternal() {
165: Set fullEntrySet = __tc_delegateEntrySet();
166: int entrySetSize = fullEntrySet.size();
167: if (entrySetSize == 0) {
168: return Collections.EMPTY_LIST;
169: }
170:
171: Object[] tmp = new Object[entrySetSize];
172: int index = -1;
173: for (Iterator i = fullEntrySet.iterator(); i.hasNext();) {
174: Map.Entry e = (Map.Entry) i.next();
175: if (((TCMapEntry) e).__tc_isValueFaultedIn()) {
176: index++;
177: tmp[index] = new ConcurrentHashMapEntrySetWrapper.EntryWrapper(
178: this , e);
179: }
180: }
181:
182: if (index < 0) {
183: return Collections.EMPTY_LIST;
184: }
185: Object[] rv = new Object[index + 1];
186: System.arraycopy(tmp, 0, rv, 0, index + 1);
187: return Arrays.asList(rv);
188: }
189:
190: /*
191: * Clearable methods
192: */
193: public int __tc_clearReferences(int toClear) {
194: if (!__tc_isManaged()) {
195: throw new AssertionError(
196: "clearReferences() called on Unmanaged ConcurrentHashMap");
197: }
198: try {
199: __tc_fullyWriteLock();
200:
201: int cleared = 0;
202: for (Iterator i = __tc_delegateEntrySet().iterator(); i
203: .hasNext()
204: && toClear > cleared;) {
205: Map.Entry e = (Map.Entry) i.next();
206: if (((TCMapEntry) e).__tc_isValueFaultedIn()
207: && e.getValue() instanceof Manageable) {
208: Manageable m = (Manageable) e.getValue();
209: TCObject tcObject = m.__tc_managed();
210: if (tcObject != null
211: && !tcObject.recentlyAccessed()) {
212: ((TCMapEntry) e).__tc_rawSetValue(tcObject
213: .getObjectID());
214: cleared++;
215: }
216: }
217: }
218: return cleared;
219: } finally {
220: __tc_fullyWriteUnlock();
221: }
222: }
223:
224: public boolean isEvictionEnabled() {
225: return evictionEnabled;
226: }
227:
228: public void setEvictionEnabled(boolean enabled) {
229: evictionEnabled = enabled;
230: }
231: }
|