@CanIgnoreReturnValue @Override public V putIfAbsent(K key, V value) { checkNotNull(key); checkNotNull(value); int hash = hash(key); return segmentFor(hash).put(key, hash, value, true); }
@CanIgnoreReturnValue @Override public V putIfAbsent(K key, V value) { checkNotNull(key); checkNotNull(value); int hash = hash(key); return segmentFor(hash).put(key, hash, value, true); }
/** Returns a fresh {@link MapMakerInternalMap} as specified by the given {@code builder}. */ static <K, V> MapMakerInternalMap<K, V, ? extends InternalEntry<K, V, ?>, ?> create( MapMaker builder) { if (builder.getKeyStrength() == Strength.STRONG && builder.getValueStrength() == Strength.STRONG) { return new MapMakerInternalMap<>(builder, StrongKeyStrongValueEntry.Helper.<K, V>instance()); } if (builder.getKeyStrength() == Strength.STRONG && builder.getValueStrength() == Strength.WEAK) { return new MapMakerInternalMap<>(builder, StrongKeyWeakValueEntry.Helper.<K, V>instance()); } if (builder.getKeyStrength() == Strength.WEAK && builder.getValueStrength() == Strength.STRONG) { return new MapMakerInternalMap<>(builder, WeakKeyStrongValueEntry.Helper.<K, V>instance()); } if (builder.getKeyStrength() == Strength.WEAK && builder.getValueStrength() == Strength.WEAK) { return new MapMakerInternalMap<>(builder, WeakKeyWeakValueEntry.Helper.<K, V>instance()); } throw new AssertionError(); }
@Override public V get(@Nullable Object key) { if (key == null) { return null; } int hash = hash(key); return segmentFor(hash).get(key, hash); }
/** * Returns the internal entry for the specified key. The entry may be computing, expired, or * partially collected. Does not impact recency ordering. */ ReferenceEntry<K, V> getEntry(@Nullable Object key) { if (key == null) { return null; } int hash = hash(key); return segmentFor(hash).getEntry(key, hash); }
@GuardedBy("Segment.this") void drainValueReferenceQueue() { Reference<? extends V> ref; int i = 0; while ((ref = valueReferenceQueue.poll()) != null) { @SuppressWarnings("unchecked") ValueReference<K, V> valueReference = (ValueReference<K, V>) ref; map.reclaimValue(valueReference); if (++i == DRAIN_MAX) { break; } } }
@GuardedBy("Segment.this") void drainKeyReferenceQueue() { Reference<? extends K> ref; int i = 0; while ((ref = keyReferenceQueue.poll()) != null) { @SuppressWarnings("unchecked") ReferenceEntry<K, V> entry = (ReferenceEntry<K, V>) ref; map.reclaimKey(entry); if (++i == DRAIN_MAX) { break; } } }
public void testClear() { MapMakerInternalMap<Object, Object, ?, ?> map = makeMap(createMapMaker().concurrencyLevel(1).initialCapacity(1)); Segment<Object, Object, ?, ?> segment = map.segments[0]; AtomicReferenceArray<? extends InternalEntry<Object, Object, ?>> table = segment.table; assertEquals(1, table.length()); Object key = new Object(); Object value = new Object(); int hash = map.hash(key); InternalEntry<Object, Object, ?> entry = segment.newEntryForTesting(key, hash, null); segment.setValueForTesting(entry, value); segment.setTableEntryForTesting(0, entry); segment.readCount.incrementAndGet(); segment.count = 1; assertSame(entry, table.get(0)); segment.clear(); assertNull(table.get(0)); assertEquals(0, segment.readCount.get()); assertEquals(0, segment.count); }
public void testSegmentPut_expand() { MapMakerInternalMap<Object, Object, ?, ?> map = makeMap(createMapMaker().concurrencyLevel(1).initialCapacity(1)); Segment<Object, Object, ?, ?> segment = map.segments[0]; assertEquals(1, segment.table.length()); int count = 1024; for (int i = 0; i < count; i++) { Object key = new Object(); Object value = new Object(); int hash = map.hash(key); assertNull(segment.put(key, hash, value, false)); assertTrue(segment.table.length() > i); } }
HashIterator() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; advance(); }
@Override public E intern(E sample) { while (true) { // trying to read the canonical... InternalEntry<E, Dummy, ?> entry = map.getEntry(sample); if (entry != null) { E canonical = entry.getKey(); if (canonical != null) { // only matters if weak/soft keys are used return canonical; } } // didn't see it, trying to put it instead... Dummy sneaky = map.putIfAbsent(sample, Dummy.VALUE); if (sneaky == null) { return sample; } else { /* Someone beat us to it! Trying again... * * Technically this loop not guaranteed to terminate, so theoretically (extremely * unlikely) this thread might starve, but even then, there is always going to be another * thread doing progress here. */ } } } }
public void testDrainKeyReferenceQueueOnWrite() { for (MapMaker maker : allWeakKeyStrengthMakers()) { MapMakerInternalMap<Object, Object, ?, ?> map = makeMap(maker.concurrencyLevel(1)); if (maker.getKeyStrength() == Strength.WEAK) { Segment<Object, Object, ?, ?> segment = map.segments[0]; Object keyOne = new Object(); int hashOne = map.hash(keyOne); Object valueOne = new Object(); Object keyTwo = new Object(); Object valueTwo = new Object(); map.put(keyOne, valueOne); InternalEntry<Object, Object, ?> entry = segment.getEntry(keyOne, hashOne); @SuppressWarnings("unchecked") Reference<Object> reference = (Reference) entry; reference.enqueue(); map.put(keyTwo, valueTwo); assertFalse(map.containsKey(keyOne)); assertFalse(map.containsValue(valueOne)); assertNull(map.get(keyOne)); assertEquals(1, map.size()); assertNull(segment.getKeyReferenceQueueForTesting().poll()); } } }
HashIterator() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; advance(); }
@Override public void putAll(Map<? extends K, ? extends V> m) { for (Entry<? extends K, ? extends V> e : m.entrySet()) { put(e.getKey(), e.getValue()); } }
@GuardedBy("this") void drainKeyReferenceQueue(ReferenceQueue<K> keyReferenceQueue) { Reference<? extends K> ref; int i = 0; while ((ref = keyReferenceQueue.poll()) != null) { @SuppressWarnings("unchecked") E entry = (E) ref; map.reclaimKey(entry); if (++i == DRAIN_MAX) { break; } } }
@GuardedBy("this") void drainValueReferenceQueue(ReferenceQueue<V> valueReferenceQueue) { Reference<? extends V> ref; int i = 0; while ((ref = valueReferenceQueue.poll()) != null) { @SuppressWarnings("unchecked") WeakValueReference<K, V, E> valueReference = (WeakValueReference<K, V, E>) ref; map.reclaimValue(valueReference); if (++i == DRAIN_MAX) { break; } } }
@Override public V remove(@Nullable Object key) { if (key == null) { return null; } int hash = hash(key); return segmentFor(hash).remove(key, hash); }
@GuardedBy("Segment.this") void drainValueReferenceQueue() { Reference<? extends V> ref; int i = 0; while ((ref = valueReferenceQueue.poll()) != null) { @SuppressWarnings("unchecked") ValueReference<K, V> valueReference = (ValueReference<K, V>) ref; map.reclaimValue(valueReference); if (++i == DRAIN_MAX) { break; } } }
@GuardedBy("Segment.this") void drainKeyReferenceQueue() { Reference<? extends K> ref; int i = 0; while ((ref = keyReferenceQueue.poll()) != null) { @SuppressWarnings("unchecked") ReferenceEntry<K, V> entry = (ReferenceEntry<K, V>) ref; map.reclaimKey(entry); if (++i == DRAIN_MAX) { break; } } }