Ejemplo n.º 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();
  }