(
K key,
int hash,
BiFunction<? super K, ? super @Nullable V, ? extends @Nullable V> function)
| 2211 | } |
| 2212 | |
| 2213 | @Nullable V compute( |
| 2214 | K key, |
| 2215 | int hash, |
| 2216 | BiFunction<? super K, ? super @Nullable V, ? extends @Nullable V> function) { |
| 2217 | ReferenceEntry<K, V> e; |
| 2218 | ValueReference<K, V> valueReference = null; |
| 2219 | ComputingValueReference<K, V> computingValueReference = null; |
| 2220 | boolean createNewEntry = true; |
| 2221 | V newValue; |
| 2222 | |
| 2223 | lock(); |
| 2224 | try { |
| 2225 | // re-read ticker once inside the lock |
| 2226 | long now = map.ticker.read(); |
| 2227 | preWriteCleanup(now); |
| 2228 | |
| 2229 | AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; |
| 2230 | int index = hash & (table.length() - 1); |
| 2231 | ReferenceEntry<K, V> first = table.get(index); |
| 2232 | |
| 2233 | for (e = first; e != null; e = e.getNext()) { |
| 2234 | K entryKey = e.getKey(); |
| 2235 | if (e.getHash() == hash |
| 2236 | && entryKey != null |
| 2237 | && map.keyEquivalence.equivalent(key, entryKey)) { |
| 2238 | valueReference = e.getValueReference(); |
| 2239 | if (map.isExpired(e, now)) { |
| 2240 | // This is a duplicate check, as preWriteCleanup already purged expired |
| 2241 | // entries, but let's accommodate an incorrect expiration queue. |
| 2242 | enqueueNotification( |
| 2243 | entryKey, |
| 2244 | hash, |
| 2245 | valueReference.get(), |
| 2246 | valueReference.getWeight(), |
| 2247 | RemovalCause.EXPIRED); |
| 2248 | } |
| 2249 | |
| 2250 | // immediately reuse invalid entries |
| 2251 | writeQueue.remove(e); |
| 2252 | accessQueue.remove(e); |
| 2253 | createNewEntry = false; |
| 2254 | break; |
| 2255 | } |
| 2256 | } |
| 2257 | |
| 2258 | // note valueReference can be an existing value or even itself another loading value if |
| 2259 | // the value for the key is already being computed. |
| 2260 | computingValueReference = new ComputingValueReference<>(valueReference); |
| 2261 | |
| 2262 | // Compute the value now, so if it throws an exception we don't change anything. |
| 2263 | newValue = computingValueReference.compute(key, function); |
| 2264 | |
| 2265 | if (e == null) { |
| 2266 | createNewEntry = true; |
| 2267 | e = newEntry(key, hash, first); |
| 2268 | e.setValueReference(computingValueReference); |
| 2269 | table.set(index, e); |
| 2270 | } else { |
nothing calls this directly
no test coverage detected