示例#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();
  }
示例#2
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");
 }
示例#3
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");
 }