void directRemove(final Bytes keyBytes, int hash2) {
      lock();
      try {
        hash2 = hashLookup.startSearch(hash2);
        while (true) {

          final int pos = hashLookup.nextPos();
          if (pos < 0) {
            return;

          } else {
            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);
            if (!keyEquals(keyBytes, tmpBytes)) continue;
            final long keyLength =
                align(keyBytes.remaining() + tmpBytes.position()); // includes the stop bit length.
            tmpBytes.position(keyLength);

            hashLookup.remove(hash2, pos);
            decrementSize();

            freeList.clear(pos);
            if (pos < nextSet) nextSet = pos;

            return;
          }
        }
      } finally {
        unlock();
      }
    }
 public Entry<K, V> getNextEntry(K prevKey) {
   try {
     int pos;
     if (prevKey == null) {
       pos = smallMap.firstPos();
     } else {
       long hash = hasher.hash(prevKey);
       pos = smallMap.nextDifferentHashNonEmptyPosition(hash);
     }
     while (true) {
       if (pos < 0) {
         return null;
       } else {
         bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
         K key = getKey();
         if (prevKey == null || !equals(key, prevKey)) {
           if (bytesMarshallable) {
             V value = (V) NativeBytes.UNSAFE.allocateInstance(vClass);
             ((BytesMarshallable) value).readMarshallable(bytes);
             return new SimpleEntry<K, V>(key, value);
           } else {
             V value = (V) bytes.readObject();
             return new SimpleEntry<K, V>(key, value);
           }
         }
       }
       pos = smallMap.nextPos();
     }
   } catch (InstantiationException e) {
     throw new AssertionError(e);
   }
 }
    void directPut(final Bytes key, final Bytes value, int hash2) {
      lock();
      try {
        hash2 = hashLookup.startSearch(hash2);
        while (true) {
          final int pos = hashLookup.nextPos();
          if (pos < 0) {
            directPutEntry(key, value, hash2);

            return;

          } else {
            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);
            if (!keyEquals(key, tmpBytes)) continue;
            final long keyLength = key.remaining();
            tmpBytes.skip(keyLength);
            appendValue(value);
            return;
          }
        }
      } finally {
        unlock();
      }
    }
 synchronized V get(long hash, K key, V value) {
   smallMap.startSearch(hash);
   while (true) {
     int pos = smallMap.nextPos();
     if (pos < 0) {
       K key2 = key instanceof CharSequence ? (K) key.toString() : key;
       final DirectStore store = map.get(key2);
       if (store == null) return null;
       bytes.storePositionAndSize(store, 0, store.size());
       break;
     } else {
       bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
       K key2 = getKey();
       if (equals(key, key2)) break;
     }
   }
   if (bytesMarshallable) {
     try {
       V v = value == null ? (V) NativeBytes.UNSAFE.allocateInstance(vClass) : value;
       ((BytesMarshallable) v).readMarshallable(bytes);
       return v;
     } catch (InstantiationException e) {
       throw new AssertionError(e);
     }
   }
   return (V) bytes.readObject();
 }
    public V remove(DirectBytes keyBytes, V value, int hash2) {
      if (hash2 == hashLookup.unsetKey()) hash2 = ~hash2;
      lock();
      try {
        hashLookup.startSearch(hash2);
        while (true) {
          int pos = hashLookup.nextInt();
          if (pos == hashLookup.unsetValue()) {
            return null;

          } else {
            long offset = entriesOffset + pos * builder.entrySize();
            tmpBytes.storePositionAndSize(bytes, offset, builder.entrySize());
            if (!keyEquals(keyBytes, tmpBytes)) continue;
            long keyLength = align(keyBytes.remaining());
            tmpBytes.skip(keyLength);
            V v =
                value == null && builder.removeReturnsNull()
                    ? null
                    : readObjectUsing(value, offset + keyLength);
            hashLookup.remove(hash2, pos);
            freeList.clear(pos);
            if (pos < nextSet) nextSet = pos;
            return v;
          }
        }
      } finally {
        unlock();
      }
    }
    public V acquire(DirectBytes keyBytes, V value, int hash2, boolean create) {
      if (hash2 == hashLookup.unsetKey()) hash2 = ~hash2;
      lock();
      try {
        hashLookup.startSearch(hash2);
        while (true) {
          int pos = hashLookup.nextInt();
          if (pos == hashLookup.unsetValue()) {
            return create ? acquireEntry(keyBytes, value, hash2) : null;

          } else {
            long offset = entriesOffset + pos * builder.entrySize();
            tmpBytes.storePositionAndSize(bytes, offset, builder.entrySize());
            long start0 = System.nanoTime();
            boolean miss = !keyEquals(keyBytes, tmpBytes);
            long time0 = System.nanoTime() - start0;
            if (time0 > 1e6)
              System.out.println("startsWith took " + time0 / 100000 / 10.0 + " ms.");
            if (miss) continue;
            long keyLength =
                align(keyBytes.remaining() + tmpBytes.position()); // includes the stop bit length.
            tmpBytes.position(keyLength);
            return readObjectUsing(value, offset + keyLength);
          }
        }
      } finally {
        unlock();
      }
    }
 K getKey() {
   if (csKey) {
     sbKey.setLength(0);
     bytes.readUTFΔ(sbKey);
     return (K) sbKey;
   }
   return (K) bytes.readObject();
 }
 private void putEntry(DirectBytes keyBytes, V value, int hash2) {
   int pos = nextFree();
   long offset = entriesOffset + pos * builder.entrySize();
   tmpBytes.storePositionAndSize(bytes, offset, builder.entrySize());
   long keyLength = keyBytes.remaining();
   tmpBytes.writeStopBit(keyLength);
   tmpBytes.write(keyBytes);
   tmpBytes.position(align(tmpBytes.position()));
   appendInstance(keyBytes, value);
   // add to index if successful.
   hashLookup.put(hash2, pos);
 }
 private void appendInstance(DirectBytes bytes, V value) {
   bytes.clear();
   if (builder.generatedValueType()) ((BytesMarshallable) value).writeMarshallable(bytes);
   else bytes.writeInstance(vClass, value);
   bytes.flip();
   if (bytes.remaining() > tmpBytes.remaining())
     throw new IllegalArgumentException(
         "Value too large for entry was "
             + bytes.remaining()
             + ", remaining: "
             + tmpBytes.remaining());
   tmpBytes.write(bytes);
 }
    /**
     * implementation for map.containsKey(Key)
     *
     * @param keyBytes the key of the entry
     * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} )
     * @return true if and entry for this key exists
     */
    boolean containsKey(final DirectBytes keyBytes, final int hash2) {
      lock();
      try {

        hashLookup.startSearch(hash2);
        while (true) {

          final int pos = hashLookup.nextPos();

          if (pos < 0) {
            return false;

          } else {

            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);

            if (!keyEquals(keyBytes, tmpBytes)) continue;

            return true;
          }
        }
      } finally {
        unlock();
      }
    }
 synchronized boolean remove(long hash, K key) {
   int h = smallMap.startSearch(hash);
   boolean found = false;
   while (true) {
     int pos = smallMap.nextPos();
     if (pos < 0) {
       break;
     }
     bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
     K key2 = getKey();
     if (equals(key, key2)) {
       usedSet.clear(pos);
       smallMap.remove(h, pos);
       found = true;
       this.size--;
       break;
     }
   }
   K key2 = key instanceof CharSequence ? (K) key.toString() : key;
   DirectStore remove = map.remove(key2);
   if (remove == null) return found;
   offHeapUsed -= remove.size();
   remove.free();
   this.size--;
   return true;
 }
 private V acquireEntry(DirectBytes keyBytes, V value, int hash2) {
   int pos = nextFree();
   long offset = entriesOffset + pos * builder.entrySize();
   tmpBytes.storePositionAndSize(bytes, offset, builder.entrySize());
   long keyLength = keyBytes.remaining();
   tmpBytes.writeStopBit(keyLength);
   tmpBytes.write(keyBytes);
   tmpBytes.position(align(tmpBytes.position()));
   tmpBytes.zeroOut(tmpBytes.position(), tmpBytes.limit());
   V v = readObjectUsing(value, offset + tmpBytes.position());
   // add to index if successful.
   hashLookup.put(hash2, pos);
   return v;
 }
 public Segment(NativeBytes bytes) {
   this.bytes = bytes;
   long start = bytes.startAddr() + SharedHashMapBuilder.SEGMENT_HEADER;
   long size = Maths.nextPower2(builder.entriesPerSegment() * 12, 16 * 8);
   NativeBytes iimmapBytes =
       new NativeBytes(tmpBytes.bytesMarshallerFactory(), start, start + size, null);
   iimmapBytes.load();
   hashLookup = new IntIntMultiMap(iimmapBytes);
   start += size;
   long bsSize = (builder.entriesPerSegment() + 63) / 64 * 8;
   NativeBytes bsBytes =
       new NativeBytes(tmpBytes.bytesMarshallerFactory(), start, start + bsSize, null);
   //            bsBytes.load();
   freeList = new SingleThreadedDirectBitSet(bsBytes);
   start += bsSize * (1 + builder.replicas());
   entriesOffset = start - bytes.startAddr();
   assert bytes.capacity() >= entriesOffset + builder.entriesPerSegment() * builder.entrySize();
 }
    public V put(DirectBytes keyBytes, V value, int hash2, boolean replaceIfPresent) {
      if (hash2 == hashLookup.unsetKey()) hash2 = ~hash2;
      lock();
      try {
        hashLookup.startSearch(hash2);
        while (true) {
          int pos = hashLookup.nextInt();
          if (pos == hashLookup.unsetValue()) {
            putEntry(keyBytes, value, hash2);
            return null;

          } else {
            long offset = entriesOffset + pos * builder.entrySize();
            tmpBytes.storePositionAndSize(bytes, offset, builder.entrySize());
            if (!keyEquals(keyBytes, tmpBytes)) continue;
            long keyLength = keyBytes.remaining();
            tmpBytes.skip(keyLength);
            long alignPosition = align(tmpBytes.position());
            tmpBytes.position(alignPosition);
            if (replaceIfPresent) {
              if (builder.putReturnsNull()) {
                appendInstance(keyBytes, value);
                return null;
              }
              V v = readObjectUsing(null, offset + alignPosition);
              tmpBytes.position(alignPosition);
              appendInstance(keyBytes, value);
              return v;

            } else {
              if (builder.putReturnsNull()) {
                return null;
              }
              return readObjectUsing(null, offset + keyLength);
            }
          }
        }
      } finally {
        unlock();
      }
    }
 /**
  * Reads from {@link this.tmpBytes} an object at {@param offset}, will reuse {@param value} if
  * possible, to reduce object creation.
  *
  * @param offset the offset to read the data from
  * @param value the object to reuse ( if possible ), if null a new object will be created an
  *     object and no reuse will occur.
  */
 @SuppressWarnings("unchecked")
 V readObjectUsing(V value, final long offset) {
   if (value instanceof Byteable) {
     ((Byteable) value).bytes(bytes, offset);
     return value;
   }
   if (generatedValueType) {
     if (value == null) value = DataValueClasses.newInstance(vClass);
     ((BytesMarshallable) value).readMarshallable(tmpBytes);
     return value;
   }
   return tmpBytes.readInstance(vClass, value);
 }
    /**
     * implementation for map.remove(Key,Value)
     *
     * @param keyBytes the key of the entry to remove
     * @param expectedValue the entry will only be removed if the {@param existingValue} equals null
     *     or the {@param existingValue} equals that of the entry.value
     * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} )
     * @return
     */
    V remove(final DirectBytes keyBytes, final V expectedValue, int hash2) {
      lock();
      try {
        hash2 = hashLookup.startSearch(hash2);
        while (true) {

          final int pos = hashLookup.nextPos();
          if (pos < 0) {
            return null;

          } else {
            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);
            if (!keyEquals(keyBytes, tmpBytes)) continue;
            final long keyLength =
                align(keyBytes.remaining() + tmpBytes.position()); // includes the stop bit length.
            tmpBytes.position(keyLength);
            V valueRemoved =
                expectedValue == null && removeReturnsNull
                    ? null
                    : readObjectUsing(null, offset + keyLength);

            if (expectedValue != null && !expectedValue.equals(valueRemoved)) return null;

            hashLookup.remove(hash2, pos);
            decrementSize();

            freeList.clear(pos);
            if (pos < nextSet) nextSet = pos;

            return valueRemoved;
          }
        }
      } finally {
        unlock();
      }
    }
    Segment(NativeBytes bytes) {
      this.bytes = bytes;

      long start = bytes.startAddr() + SharedHashMapBuilder.SEGMENT_HEADER;
      final NativeBytes iimmapBytes = new NativeBytes(null, start, start + sizeOfMultiMap(), null);
      iimmapBytes.load();
      hashLookup = new IntIntMultiMap(iimmapBytes);
      start += sizeOfMultiMap();
      final NativeBytes bsBytes =
          new NativeBytes(tmpBytes.bytesMarshallerFactory(), start, start + sizeOfBitSets(), null);
      freeList = new SingleThreadedDirectBitSet(bsBytes);
      start += numberOfBitSets() * sizeOfBitSets();
      entriesOffset = start - bytes.startAddr();
      assert bytes.capacity() >= entriesOffset + entriesPerSegment * entrySize;
    }
 synchronized boolean containsKey(long hash, K key) {
   smallMap.startSearch(hash);
   while (true) {
     int pos = smallMap.nextPos();
     if (pos < 0) {
       K key2 = key instanceof CharSequence ? (K) key.toString() : key;
       return map.containsKey(key2);
     }
     bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
     K key2 = getKey();
     if (equals(key, key2)) {
       return true;
     }
   }
 }
 void appendValue(final Bytes value) {
   if (value.remaining() + 4 > tmpBytes.remaining())
     throw new IllegalArgumentException(
         "Value too large for entry was "
             + (value.remaining() + 4)
             + ", remaining: "
             + tmpBytes.remaining());
   tmpBytes.writeStopBit(value.remaining());
   tmpBytes.position(align(tmpBytes.position()));
   tmpBytes.write(value);
 }
    /**
     * implementation for map.put(Key,Value)
     *
     * @param keyBytes
     * @param value
     * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} )
     * @param replaceIfPresent
     * @return
     */
    V put(final DirectBytes keyBytes, final V value, int hash2, boolean replaceIfPresent) {
      lock();
      try {
        hash2 = hashLookup.startSearch(hash2);
        while (true) {
          final int pos = hashLookup.nextPos();
          if (pos < 0) {
            putEntry(keyBytes, value, hash2);

            return null;

          } else {
            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);
            if (!keyEquals(keyBytes, tmpBytes)) continue;
            final long keyLength = keyBytes.remaining();
            tmpBytes.skip(keyLength);
            if (replaceIfPresent) {
              if (putReturnsNull) {
                appendInstance(keyBytes, value);
                return null;
              }
              long valuePosition = tmpBytes.position();
              tmpBytes.readStopBit();
              final long alignPosition = align(tmpBytes.position());
              tmpBytes.position(alignPosition);
              final V v = readObjectUsing(null, offset + alignPosition);
              tmpBytes.position(valuePosition);
              appendInstance(keyBytes, value);
              return v;

            } else {
              if (putReturnsNull) {
                return null;
              }

              return readObjectUsing(null, offset + keyLength);
            }
          }
        }
      } finally {
        unlock();
      }
    }
    /**
     * implementation for map.replace(Key,Value) and map.replace(Key,Old,New)
     *
     * @param keyBytes the key of the entry to be replaced
     * @param expectedValue the expected value to replaced
     * @param newValue the new value that will only be set if the existing value in the map equals
     *     the {@param expectedValue} or {@param expectedValue} is null
     * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} )
     * @return null if the value was not replaced, else the value that is replaced is returned
     */
    V replace(
        final DirectBytes keyBytes, final V expectedValue, final V newValue, final int hash2) {
      lock();
      try {

        hashLookup.startSearch(hash2);
        while (true) {

          final int pos = hashLookup.nextPos();

          if (pos < 0) {
            return null;

          } else {

            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);

            if (!keyEquals(keyBytes, tmpBytes)) continue;

            final long keyLength = keyBytes.remaining();
            tmpBytes.skip(keyLength);
            long valuePosition = tmpBytes.position();
            tmpBytes.readStopBit();
            final long alignPosition = align(tmpBytes.position());
            tmpBytes.position(alignPosition);

            final V valueRead = readObjectUsing(null, offset + keyLength);

            if (valueRead == null) return null;

            if (expectedValue == null || expectedValue.equals(valueRead)) {
              tmpBytes.position(valuePosition);
              appendInstance(keyBytes, newValue);
            }

            return valueRead;
          }
        }
      } finally {
        unlock();
      }
    }
 public K getNextKey(K prevKey) {
   int pos;
   if (prevKey == null) {
     pos = smallMap.firstPos();
   } else {
     long hash = hasher.hash(prevKey);
     pos = smallMap.nextDifferentHashNonEmptyPosition(hash);
   }
   while (true) {
     if (pos < 0) {
       return null;
     } else {
       bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
       K key = getKey();
       if (prevKey == null || !equals(key, prevKey)) {
         return key;
       }
     }
     pos = smallMap.nextPos();
   }
 }
    /**
     * used to acquire and object of type V from the map,
     *
     * <p>when {@param create }== true, this method is equivalent to :
     *
     * <pre>
     * Object value = map.get("Key");
     *
     * if ( counter == null ) {
     *    value = new Object();
     *    map.put("Key", value);
     * }
     *
     * return value;
     * </pre>
     *
     * @param keyBytes the key of the entry
     * @param value an object to be reused, null creates a new object.
     * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} )
     * @param create false - if the {@keyBytes} can not be found null will be returned, true - if
     *     the {@keyBytes} can not be found an value will be acquired
     * @return an entry.value whose entry.key equals {@param keyBytes}
     */
    V acquire(DirectBytes keyBytes, V value, int hash2, boolean create) {
      lock();
      try {
        hash2 = hashLookup.startSearch(hash2);
        while (true) {
          int pos = hashLookup.nextPos();
          if (pos < 0) {
            return create ? acquireEntry(keyBytes, value, hash2) : null;

          } else {
            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);
            final boolean miss;
            if (LOGGER.isLoggable(Level.FINE)) {
              final long start0 = System.nanoTime();
              miss = !keyEquals(keyBytes, tmpBytes);
              final long time0 = System.nanoTime() - start0;
              if (time0 > 1e6) LOGGER.fine("startsWith took " + time0 / 100000 / 10.0 + " ms.");
            } else {
              miss = !keyEquals(keyBytes, tmpBytes);
            }
            if (miss) continue;
            long valueLengthOffset = keyBytes.remaining() + tmpBytes.position();
            tmpBytes.position(valueLengthOffset);
            // skip the value length
            // todo use the value length to limit reading below
            long valueLength = tmpBytes.readStopBit();
            final long valueOffset = align(tmpBytes.position()); // includes the stop bit length.
            tmpBytes.position(valueOffset);
            return readObjectUsing(value, offset + valueOffset);
          }
        }
      } finally {
        unlock();
      }
    }
    synchronized void put(long hash, K key, V value, boolean ifPresent, boolean ifAbsent) {
      // search for the previous entry
      int h = smallMap.startSearch(hash);
      boolean foundSmall = false, foundLarge = false;
      while (true) {
        int pos = smallMap.nextPos();
        if (pos < 0) {
          K key2 = key instanceof CharSequence ? (K) key.toString() : key;
          final DirectStore store = map.get(key2);
          if (store == null) {
            if (ifPresent && !ifAbsent) return;
            break;
          }
          if (ifAbsent) return;
          bytes.storePositionAndSize(store, 0, store.size());
          foundLarge = true;
          break;
        } else {
          bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
          K key2 = getKey();
          if (equals(key, key2)) {
            if (ifAbsent && !ifPresent) return;
            foundSmall = true;
            break;
          }
        }
      }

      tmpBytes.clear();
      if (csKey)
        //noinspection ConstantConditions
        tmpBytes.writeUTFΔ((CharSequence) key);
      else tmpBytes.writeObject(key);
      long startOfValuePos = tmpBytes.position();
      if (bytesMarshallable) ((BytesMarshallable) value).writeMarshallable(tmpBytes);
      else tmpBytes.writeObject(value);
      long size = tmpBytes.position();
      if (size <= smallEntrySize) {
        if (foundSmall) {
          bytes.position(0);
          bytes.write(tmpBytes, 0, size);
          return;
        } else if (foundLarge) {
          remove(hash, key);
        }
        // look for a free spot.
        int position = h & (entriesPerSegment - 1);
        int free = usedSet.nextClearBit(position);
        if (free >= entriesPerSegment) free = usedSet.nextClearBit(0);
        if (free < entriesPerSegment) {
          bytes.storePositionAndSize(store, free * smallEntrySize, smallEntrySize);
          bytes.write(tmpBytes, 0, size);
          smallMap.put(h, free);
          usedSet.set(free);
          this.size++;
          return;
        }
      }
      if (foundSmall) {
        remove(hash, key);
      } else if (foundLarge) {
        // can it be reused.
        if (bytes.capacity() <= size || bytes.capacity() - size < (size >> 3)) {
          bytes.write(tmpBytes, startOfValuePos, size);
          return;
        }
        remove(hash, key);
      }
      size = size - startOfValuePos;
      DirectStore store = new DirectStore(bmf, size);
      bytes.storePositionAndSize(store, 0, size);
      bytes.write(tmpBytes, startOfValuePos, size);
      K key2 = key instanceof CharSequence ? (K) key.toString() : key;
      map.put(key2, store);
      offHeapUsed += size;
      this.size++;
    }
 boolean keyEquals(Bytes keyBytes, MultiStoreBytes tmpBytes) {
   // check the length is the same.
   long keyLength = tmpBytes.readStopBit();
   return keyLength == keyBytes.remaining() && tmpBytes.startsWith(keyBytes);
 }
 private void writeKey(Bytes keyBytes, long offset) {
   tmpBytes.storePositionAndSize(bytes, offset, entrySize);
   long keyLength = keyBytes.remaining();
   tmpBytes.writeStopBit(keyLength);
   tmpBytes.write(keyBytes);
 }
    /**
     * @param keyBytes
     * @param value
     * @param hash2
     * @return
     */
    V acquireEntry(DirectBytes keyBytes, V value, int hash2) {
      value = createValueIfNull(value);

      final int pos = nextFree();
      final long offset = entriesOffset + pos * entrySize;
      tmpBytes.storePositionAndSize(bytes, offset, entrySize);
      final long keyLength = keyBytes.remaining();
      tmpBytes.writeStopBit(keyLength);
      tmpBytes.write(keyBytes);
      if (value instanceof Byteable) {
        Byteable byteable = (Byteable) value;
        int length = byteable.maxSize();
        tmpBytes.writeStopBit(length);
        tmpBytes.position(align(tmpBytes.position()));
        if (length > tmpBytes.remaining())
          throw new IllegalStateException(
              "Not enough space left in entry for value, needs "
                  + length
                  + " but only "
                  + tmpBytes.remaining()
                  + " left");
        tmpBytes.zeroOut(tmpBytes.position(), tmpBytes.position() + length);
        byteable.bytes(bytes, offset + tmpBytes.position());
      } else {
        appendInstance(keyBytes, value);
      }
      // add to index if successful.
      hashLookup.put(hash2, pos);
      incrementSize();
      return value;
    }