53 |
|
* (STRONG, |
54 |
|
* new Equivalence<Person>() { |
55 |
|
* public boolean equal(Person k, Object x) { |
56 |
< |
* return x instanceOf Person && k.name.equals(((Person)x).name); |
56 |
> |
* return x instanceof Person && k.name.equals(((Person)x).name); |
57 |
|
* } |
58 |
|
* public int hash(Object x) { |
59 |
< |
* return (x instanceOf Person)? ((Person)x).name.hashCode() : 0; |
59 |
> |
* return (x instanceof Person)? ((Person)x).name.hashCode() : 0; |
60 |
|
* } |
61 |
|
* }, |
62 |
|
* STRONG, EQUALS, 0); |
81 |
|
* via a background thread common across all maps. Because of the |
82 |
|
* potential for asynchronous clearing of References, methods such as |
83 |
|
* <code>containsValue</code> have weaker guarantees than you might |
84 |
< |
* expect even in the absence of other explicity concurrent |
84 |
> |
* expect even in the absence of other explicitly concurrent |
85 |
|
* operations. For example <code>containsValue(value)</code> may |
86 |
|
* return true even if <code>value</code> is no longer available upon |
87 |
|
* return from the method. |
275 |
|
*/ |
276 |
|
static interface NodeFactory extends Serializable { |
277 |
|
/** |
278 |
< |
* Creates and returns a Node using the given parameters |
278 |
> |
* Creates and returns a Node using the given parameters. |
279 |
> |
* |
280 |
|
* @param locator an opaque immutable locator for this node |
281 |
< |
* @parem key the (nonnull) immutable key |
282 |
< |
* @parem value the (nonnull) volatile value; |
283 |
< |
* @param cchm the table creating this node. |
281 |
> |
* @param key the (non-null) immutable key |
282 |
> |
* @param value the (non-null) volatile value |
283 |
> |
* @param cchm the table creating this node |
284 |
|
* @param linkage an opaque volatile linkage for maintaining this node |
285 |
|
*/ |
286 |
|
Node newNode(int locator, Object key, Object value, |
304 |
|
static interface Node extends Reclaimable { |
305 |
|
/** |
306 |
|
* Returns the key established during the creation of this node. |
307 |
< |
* Note: This method is named "get" rether than "getKey" |
307 |
> |
* Note: This method is named "get" rather than "getKey" |
308 |
|
* to simplify usage of Reference keys. |
309 |
|
* @return the key |
310 |
|
*/ |
333 |
|
void setValue(Object value); |
334 |
|
|
335 |
|
/** |
336 |
< |
* Returns the lonkage established during the creation of this |
336 |
> |
* Returns the linkage established during the creation of this |
337 |
|
* node or, if since updated, the linkage set by the most |
338 |
|
* recent call to setLinkage. |
339 |
|
* @return the linkage |
533 |
|
int sc = (int)((1L + (4L * es) / 3) >>> SEGMENT_BITS); |
534 |
|
if (sc < MIN_SEGMENT_CAPACITY) |
535 |
|
sc = MIN_SEGMENT_CAPACITY; |
536 |
< |
else if (sc > MAX_SEGMENT_CAPACITY) |
537 |
< |
sc = MAX_SEGMENT_CAPACITY; |
538 |
< |
this.initialSegmentCapacity = sc; |
536 |
> |
int capacity = MIN_SEGMENT_CAPACITY; // ensure power of two |
537 |
> |
while (capacity < sc) |
538 |
> |
capacity <<= 1; |
539 |
> |
if (capacity > MAX_SEGMENT_CAPACITY) |
540 |
> |
capacity = MAX_SEGMENT_CAPACITY; |
541 |
> |
this.initialSegmentCapacity = capacity; |
542 |
|
} |
543 |
|
this.segments = (Segment[])new Segment[NSEGMENTS]; |
544 |
|
} |
633 |
|
|
634 |
|
/** |
635 |
|
* Returns the segment for possibly inserting into the table |
636 |
< |
* associated with given hash, constructing it if necesary. |
636 |
> |
* associated with given hash, constructing it if necessary. |
637 |
|
* @param hash the hash code for the key |
638 |
|
* @return the segment |
639 |
|
*/ |
642 |
|
int index = (hash >>> SEGMENT_SHIFT) & SEGMENT_MASK; |
643 |
|
Segment seg = segs[index]; |
644 |
|
if (seg == null) { |
645 |
< |
synchronized(segs) { |
645 |
> |
synchronized (segs) { |
646 |
|
seg = segs[index]; |
647 |
|
if (seg == null) { |
648 |
|
seg = new Segment(); |
700 |
|
* if no such mapping exists |
701 |
|
* |
702 |
|
* @param key possible key |
703 |
< |
* @return the value associated with the kew or <tt>null</tt> if |
703 |
> |
* @return the value associated with the key or <tt>null</tt> if |
704 |
|
* there is no mapping. |
705 |
|
* @throws NullPointerException if the specified key is null |
706 |
|
*/ |
716 |
|
} |
717 |
|
|
718 |
|
/** |
719 |
< |
* Share dimplementation for put, putIfAbsent |
719 |
> |
* Shared implementation for put, putIfAbsent |
720 |
|
*/ |
721 |
|
final V doPut(K key, V value, boolean onlyIfNull) { |
722 |
|
if (key == null || value == null) |
959 |
|
while (p != null) { |
960 |
|
Node n = p.getLinkage(); |
961 |
|
if (p.get() != null && p.getValue() != null) { |
962 |
+ |
pred = p; |
963 |
+ |
p = n; |
964 |
+ |
} |
965 |
+ |
else { |
966 |
|
if (pred == null) |
967 |
|
tab[i] = n; |
968 |
|
else |
970 |
|
seg.decrementCount(); |
971 |
|
p = n; |
972 |
|
} |
965 |
– |
else { |
966 |
– |
pred = p; |
967 |
– |
p = n; |
968 |
– |
} |
973 |
|
} |
974 |
|
} |
975 |
|
} finally { |
1082 |
|
* </pre> |
1083 |
|
* |
1084 |
|
* except that the action is performed atomically. Some |
1085 |
< |
* attemmpted operations on this map by other threads may be |
1085 |
> |
* attempted operations on this map by other threads may be |
1086 |
|
* blocked while computation is in progress. Because this function |
1087 |
|
* is invoked within atomicity control, the computation should be |
1088 |
|
* short and simple. The most common usage is to construct a new |
1149 |
|
* return remove(key); |
1150 |
|
* </pre> |
1151 |
|
* |
1152 |
< |
* except that the action is performed atomically. Some attemmpted |
1152 |
> |
* except that the action is performed atomically. Some attempted |
1153 |
|
* operations on this map by other threads may be blocked while |
1154 |
|
* computation is in progress. |
1155 |
|
* |
1558 |
|
* for each key-value mapping, followed by a null pair. |
1559 |
|
* The key-value mappings are emitted in no particular order. |
1560 |
|
*/ |
1561 |
< |
private void writeObject(java.io.ObjectOutputStream s) throws IOException { |
1561 |
> |
private void writeObject(java.io.ObjectOutputStream s) throws IOException { |
1562 |
|
s.defaultWriteObject(); |
1563 |
|
for (Map.Entry<K,V> e : entrySet()) { |
1564 |
|
s.writeObject(e.getKey()); |
1573 |
|
* @param s the stream |
1574 |
|
*/ |
1575 |
|
private void readObject(java.io.ObjectInputStream s) |
1576 |
< |
throws IOException, ClassNotFoundException { |
1576 |
> |
throws IOException, ClassNotFoundException { |
1577 |
|
s.defaultReadObject(); |
1578 |
|
this.segments = (Segment[])(new Segment[NSEGMENTS]); |
1579 |
|
for (;;) { |
2101 |
|
final int locator; |
2102 |
|
final CustomConcurrentHashMap cchm; |
2103 |
|
WeakKeyNode(int locator, Object key, CustomConcurrentHashMap cchm) { |
2104 |
< |
super(key); |
2104 |
> |
super(key, getReclamationQueue()); |
2105 |
|
this.locator = locator; |
2106 |
|
this.cchm = cchm; |
2107 |
|
} |
2396 |
|
final int locator; |
2397 |
|
final CustomConcurrentHashMap cchm; |
2398 |
|
SoftKeyNode(int locator, Object key, CustomConcurrentHashMap cchm) { |
2399 |
< |
super(key); |
2399 |
> |
super(key, getReclamationQueue()); |
2400 |
|
this.locator = locator; |
2401 |
|
this.cchm = cchm; |
2402 |
|
} |
2984 |
|
|
2985 |
|
// Temporary Unsafe mechanics for preliminary release |
2986 |
|
|
2987 |
< |
static final Unsafe _unsafe; |
2987 |
> |
static final Unsafe UNSAFE; |
2988 |
|
static final long tableBase; |
2989 |
|
static final int tableShift; |
2990 |
|
static final long segmentsBase; |
3015 |
|
|
3016 |
|
static { |
3017 |
|
try { |
3018 |
< |
_unsafe = getUnsafe(); |
3019 |
< |
tableBase = _unsafe.arrayBaseOffset(Node[].class); |
3020 |
< |
int s = _unsafe.arrayIndexScale(Node[].class); |
3018 |
> |
UNSAFE = getUnsafe(); |
3019 |
> |
tableBase = UNSAFE.arrayBaseOffset(Node[].class); |
3020 |
> |
int s = UNSAFE.arrayIndexScale(Node[].class); |
3021 |
|
if ((s & (s-1)) != 0) |
3022 |
|
throw new Error("data type scale not a power of two"); |
3023 |
|
tableShift = 31 - Integer.numberOfLeadingZeros(s); |
3024 |
< |
segmentsBase = _unsafe.arrayBaseOffset(Segment[].class); |
3025 |
< |
s = _unsafe.arrayIndexScale(Segment[].class); |
3024 |
> |
segmentsBase = UNSAFE.arrayBaseOffset(Segment[].class); |
3025 |
> |
s = UNSAFE.arrayIndexScale(Segment[].class); |
3026 |
|
if ((s & (s-1)) != 0) |
3027 |
|
throw new Error("data type scale not a power of two"); |
3028 |
|
segmentsShift = 31 - Integer.numberOfLeadingZeros(s); |
3034 |
|
// Fenced store into segment table array. Unneeded when we have Fences |
3035 |
|
static final void storeNode(Node[] table, |
3036 |
|
int i, Node r) { |
3037 |
< |
_unsafe.putOrderedObject(table, (i << tableShift) + tableBase, r); |
3037 |
> |
long nodeOffset = ((long) i << tableShift) + tableBase; |
3038 |
> |
UNSAFE.putOrderedObject(table, nodeOffset, r); |
3039 |
|
} |
3040 |
|
|
3041 |
|
static final void storeSegment(Segment[] segs, |
3042 |
|
int i, Segment s) { |
3043 |
< |
_unsafe.putOrderedObject(segs, (i << segmentsShift) + segmentsBase, s); |
3043 |
> |
long segmentOffset = ((long) i << segmentsShift) + segmentsBase; |
3044 |
> |
UNSAFE.putOrderedObject(segs, segmentOffset, s); |
3045 |
|
} |
3046 |
|
|
3047 |
|
|