Example #1
0
  final void splitSegmentAndPut(SmoothieMap<K, V> map, long hash, K key, V value) {
    int mc = map.modCount;
    cancelAllocBeyondCapacity(map);

    int segments = map.segments();
    int tierDiff = map.segmentsTier - this.tier;
    // Double segments array, if needed
    if (tierDiff == 0) {
      map.doubleSegments();
      segments *= 2;
      tierDiff = 1;
    }

    // Create a new Segment and replace half indexes pointing to the old segment with
    // refs to the new
    int segmentOccursEach = segments >>> tierDiff;
    int lowestSegmentIndex = (int) (hash & (segmentOccursEach - 1));
    int newTier = this.tier += 1;
    Segment<K, V> higherSegment = map.makeSegment(newTier);
    for (int segmentIndex = lowestSegmentIndex + segmentOccursEach;
        segmentIndex < segments;
        segmentIndex += segmentOccursEach * 2) {
      map.segments[segmentIndex] = higherSegment;
    }

    // Rebalance entries between two segments
    int balance = 0;
    for (long slotIndex = 0, slot; slotIndex < HASH_TABLE_SIZE; slotIndex++) {
      if ((slot = readSlot(slotIndex)) != 0) {
        long allocIndex;
        K k;
        long kHash = map.keyHashCode(k = readKey(allocIndex = allocIndex(slot)));
        if ((kHash & segmentOccursEach) != 0) {
          V v = readValue(allocIndex);
          eraseAlloc(allocIndex);
          if (shiftRemove(slotIndex) != slotIndex) slotIndex--; // don't skip shifted slot
          higherSegment.putOnSplit(map, kHash, k, v);
          balance++;
        }
      }
    }
    // Check rebalanced something, otherwise we are going to split segments infinitely
    // ending up with OutOfMemoryError
    if (balance == 0) checkHashCodesAreNotAllSame(map);
    if (balance >= map.allocCapacity) higherSegment.checkHashCodesAreNotAllSame(map);

    // Finally, put the entry
    Segment<K, V> segmentForPut;
    segmentForPut = (hash & segmentOccursEach) != 0 ? higherSegment : this;
    segmentForPut.put(map, hash, key, value, false);
    mc++;

    if (mc != map.modCount) throw new ConcurrentModificationException();
  }
Example #2
0
 final V merge(
     SmoothieMap<K, V> map,
     long hash,
     K key,
     V value,
     BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
   long slotIndex, slot, allocIndex, storedHash = storedHash(hash);
   K k;
   V oldValue;
   for (slotIndex = slotIndex(hash);
       (slot = readSlot(slotIndex)) != 0;
       slotIndex = nextSlotIndex(slotIndex)) {
     if (hash(slot) == storedHash
         && ((k = readKey((allocIndex = allocIndex(slot)))) == key
             || (key != null && map.keysEqual(key, k)))) {
       if ((oldValue = readValue(allocIndex)) == null
           || (value = remappingFunction.apply(oldValue, value)) != null) {
         writeValue(allocIndex, value);
         return value;
       } else {
         remove(map, slotIndex, allocIndex);
         return null;
       }
     }
   }
   insert(map, hash, key, value, slotIndex, storedHash);
   return value;
 }
Example #3
0
 final void clear(SmoothieMap<K, V> map) {
   U.setMemory(this, HASH_TABLE_OFFSET, HASH_TABLE_SIZE * HASH_TABLE_SLOT_SIZE, (byte) 0);
   map.size -= size();
   for (long allocIndex = 1; allocIndex <= map.allocCapacity; allocIndex++) {
     writeKey(allocIndex, null);
     writeValue(allocIndex, null);
   }
   bitSet = CLEAR_BIT_SET;
 }
Example #4
0
 final void iterationRemove(SmoothieMap<K, V> map, K key, long allocIndex) {
   long slotIndex, slot, hash = map.keyHashCode(key);
   long storedHash = storedHash(hash);
   for (slotIndex = slotIndex(hash);
       (slot = readSlot(slotIndex)) != 0;
       slotIndex = nextSlotIndex(slotIndex)) {
     if (hash(slot) == storedHash && allocIndex(slot) == allocIndex) {
       remove(map, slotIndex, allocIndex);
       return;
     }
   }
   throw new ConcurrentModificationException("Unable to find entry in segment's hash table");
 }
Example #5
0
 /**
  * @param matchValue {@code true} if should compare the mapped value to the given {@code value}
  *     before remove
  */
 final long remove(
     SmoothieMap<K, V> map, long hash, Object key, Object value, boolean matchValue) {
   long slotIndex, slot, allocIndex, storedHash = storedHash(hash);
   K k;
   V v;
   for (slotIndex = slotIndex(hash);
       (slot = readSlot(slotIndex)) != 0;
       slotIndex = nextSlotIndex(slotIndex)) {
     if (hash(slot) == storedHash
         && ((k = readKey((allocIndex = allocIndex(slot)))) == key
             || (key != null && map.keysEqual(key, k)))) {
       if (!matchValue
           || (v = readValue(allocIndex)) == value
           || (value != null && map.valuesEqual(value, v))) {
         removeButAlloc(map, slotIndex);
         return allocIndex;
       } else {
         return 0;
       }
     }
   }
   return 0;
 }
Example #6
0
 /** @return allocation index, or 0 if not found */
 final long find(SmoothieMap<K, V> map, long hash, Object key) {
   long slotIndex, slot, allocIndex, storedHash = storedHash(hash);
   K k;
   for (slotIndex = slotIndex(hash);
       (slot = readSlot(slotIndex)) != 0;
       slotIndex = nextSlotIndex(slotIndex)) {
     if (hash(slot) == storedHash
         && ((k = readKey((allocIndex = allocIndex(slot)))) == key
             || (key != null && map.keysEqual(key, k)))) {
       return allocIndex;
     }
   }
   return 0;
 }
Example #7
0
 final boolean containsValue(SmoothieMap<K, V> map, V value) {
   V v;
   for (long a,
           tail,
           allocations = (a = ~bitSet) << (tail = Long.numberOfLeadingZeros(a)),
           allocIndex = 64 - tail;
       allocations != 0;
       allocations <<= 1, allocIndex--) {
     if (allocations < 0) {
       if (((v = readValue(allocIndex)) == value
           || (value != null && map.valuesEqual(value, v)))) {
         return true;
       }
     }
   }
   return false;
 }
Example #8
0
 final V put(SmoothieMap<K, V> map, long hash, K key, V value, boolean onlyIfAbsent) {
   long slotIndex, slot, allocIndex, storedHash = storedHash(hash);
   K k;
   V oldValue;
   for (slotIndex = slotIndex(hash);
       (slot = readSlot(slotIndex)) != 0;
       slotIndex = nextSlotIndex(slotIndex)) {
     if (hash(slot) == storedHash
         && ((k = readKey((allocIndex = allocIndex(slot)))) == key
             || (key != null && map.keysEqual(key, k)))) {
       oldValue = readValue(allocIndex);
       if (!onlyIfAbsent || oldValue == null) writeValue(allocIndex, value);
       return oldValue;
     }
   }
   insert(map, hash, key, value, slotIndex, storedHash);
   return null;
 }
Example #9
0
 private void checkHashCodesAreNotAllSame(SmoothieMap<K, V> map) {
   long firstHash = -1;
   for (long slotIndex = 0, slot; slotIndex < HASH_TABLE_SIZE; slotIndex++) {
     if ((slot = readSlot(slotIndex)) != 0) {
       long kHash = map.keyHashCode(readKey(allocIndex(slot)));
       kHash &= GUARANTEED_JAVA_ARRAY_POWER_OF_TWO_CAPACITY - 1;
       if (firstHash < 0) firstHash = kHash;
       if (kHash != firstHash) return;
     }
   }
   // we checked all keys and all hashes collide
   throw new IllegalStateException(
       map.allocCapacity
           + " inserted keys has "
           + Integer.numberOfTrailingZeros(GUARANTEED_JAVA_ARRAY_POWER_OF_TWO_CAPACITY)
           + " lowest bits of hash code\n"
           + "colliding, try to override SmoothieMap.keyHashCode() and implement a hash\n"
           + "function with better distribution");
 }
Example #10
0
 final V computeIfAbsent(
     SmoothieMap<K, V> map, long hash, K key, Function<? super K, ? extends V> mappingFunction) {
   long slotIndex, slot, allocIndex, storedHash = storedHash(hash);
   K k;
   V value;
   for (slotIndex = slotIndex(hash);
       (slot = readSlot(slotIndex)) != 0;
       slotIndex = nextSlotIndex(slotIndex)) {
     if (hash(slot) == storedHash
         && ((k = readKey((allocIndex = allocIndex(slot)))) == key
             || (key != null && map.keysEqual(key, k)))) {
       if ((value = readValue(allocIndex)) != null) return value;
       if ((value = mappingFunction.apply(key)) != null) writeValue(allocIndex, value);
       return value;
     }
   }
   if ((value = mappingFunction.apply(key)) != null)
     insert(map, hash, key, value, slotIndex, storedHash);
   return value;
 }
Example #11
0
 final void putOnSplit(SmoothieMap<K, V> map, long hash, K key, V value) {
   long slotIndex, slot, allocIndex, storedHash = storedHash(hash);
   K k;
   for (slotIndex = slotIndex(hash);
       (slot = readSlot(slotIndex)) != 0;
       slotIndex = nextSlotIndex(slotIndex)) {
     if (hash(slot) == storedHash
         && ((k = readKey((allocIndex(slot)))) == key || (key != null && map.keysEqual(key, k)))) {
       throw new IllegalStateException(
           "When inserting entries into newly split segment it could not find\n"
               + "a duplicate key. It means either SmoothieMap is updated\n"
               + "concurrently OR keys are mutable and keyHashCode() and\n"
               + "keysEqual() calls return different results in time, applied to\n"
               + "the same arguments.");
     }
   }
   if ((allocIndex = alloc()) <= map.allocCapacity) {
     writeEntry(key, value, slotIndex, storedHash, allocIndex);
   } else {
     throw new ConcurrentModificationException(
         "When inserting entries into newly split segment it could be filled up "
             + "only concurrently");
   }
 }