Expands the table if possible.
()
| 2989 | */ |
| 2990 | |
| 2991 | @GuardedBy("this") |
| 2992 | void expand() { |
| 2993 | AtomicReferenceArray<ReferenceEntry<K, V>> oldTable = table; |
| 2994 | int oldCapacity = oldTable.length(); |
| 2995 | if (oldCapacity >= MAXIMUM_CAPACITY) { |
| 2996 | return; |
| 2997 | } |
| 2998 | |
| 2999 | /* |
| 3000 | * Reclassify nodes in each list to new Map. Because we are using power-of-two expansion, the |
| 3001 | * elements from each bin must either stay at same index, or move with a power of two offset. |
| 3002 | * We eliminate unnecessary node creation by catching cases where old nodes can be reused |
| 3003 | * because their next fields won't change. Statistically, at the default threshold, only about |
| 3004 | * one-sixth of them need cloning when a table doubles. The nodes they replace will be garbage |
| 3005 | * collectable as soon as they are no longer referenced by any reader thread that may be in |
| 3006 | * the midst of traversing table right now. |
| 3007 | */ |
| 3008 | |
| 3009 | int newCount = count; |
| 3010 | AtomicReferenceArray<ReferenceEntry<K, V>> newTable = newEntryArray(oldCapacity << 1); |
| 3011 | threshold = newTable.length() * 3 / 4; |
| 3012 | int newMask = newTable.length() - 1; |
| 3013 | for (int oldIndex = 0; oldIndex < oldCapacity; ++oldIndex) { |
| 3014 | // We need to guarantee that any existing reads of old Map can |
| 3015 | // proceed. So we cannot yet null out each bin. |
| 3016 | ReferenceEntry<K, V> head = oldTable.get(oldIndex); |
| 3017 | if (head != null) { |
| 3018 | ReferenceEntry<K, V> next = head.getNext(); |
| 3019 | int headIndex = head.getHash() & newMask; |
| 3020 | |
| 3021 | // Single node on list |
| 3022 | if (next == null) { |
| 3023 | newTable.set(headIndex, head); |
| 3024 | } |
| 3025 | else { |
| 3026 | // Reuse the consecutive sequence of nodes with the same target |
| 3027 | // index from the end of the list. tail points to the first |
| 3028 | // entry in the reusable list. |
| 3029 | ReferenceEntry<K, V> tail = head; |
| 3030 | int tailIndex = headIndex; |
| 3031 | for (ReferenceEntry<K, V> e = next; e != null; e = e.getNext()) { |
| 3032 | int newIndex = e.getHash() & newMask; |
| 3033 | if (newIndex != tailIndex) { |
| 3034 | // The index changed. We'll need to copy the previous entry. |
| 3035 | tailIndex = newIndex; |
| 3036 | tail = e; |
| 3037 | } |
| 3038 | } |
| 3039 | newTable.set(tailIndex, tail); |
| 3040 | |
| 3041 | // Clone nodes leading up to the tail. |
| 3042 | for (ReferenceEntry<K, V> e = head; e != tail; e = e.getNext()) { |
| 3043 | int newIndex = e.getHash() & newMask; |
| 3044 | ReferenceEntry<K, V> newNext = newTable.get(newIndex); |
| 3045 | ReferenceEntry<K, V> newFirst = copyEntry(e, newNext); |
| 3046 | if (newFirst != null) { |
| 3047 | newTable.set(newIndex, newFirst); |
| 3048 | } else { |
no test coverage detected