private @Nullable Value doGet(Key key) throws IOException {
    flushAppendCache(key);

    myEnumerator.lockStorageRead();
    final long valueOffset;
    final int id;
    try {
      if (myDirectlyStoreLongFileOffsetMode) {
        valueOffset = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
        if (myIntMapping) {
          //noinspection unchecked
          return (Value)(Integer)(int)valueOffset;
        }
        id = -1;
      }
      else {
        id = myEnumerator.tryEnumerate(key);
        if (id == DataEnumerator.NULL_ID) {
          return null;
        }

        if (myIntMapping) {
          //noinspection unchecked
          return (Value)(Integer)myEnumerator.myCollisionResolutionStorage.getInt(id + myParentValueRefOffset);
        }

        valueOffset = readValueId(id);
      }

      if (valueOffset == NULL_ADDR) {
        return null;
      }
    }
    finally {
      myEnumerator.unlockStorageRead();
    }

    final PersistentHashMapValueStorage.ReadResult readResult = myValueStorage.readBytes(valueOffset);

    final Value valueRead;
    try (DataInputStream input = new DataInputStream(new UnsyncByteArrayInputStream(readResult.buffer))) {
      valueRead = myValueExternalizer.read(input);
    }

    if (myValueStorage.performChunksCompaction(readResult.chunksCount)) {
      long newValueOffset = myValueStorage.compactChunks(new AppendablePersistentMap.ValueDataAppender() {
        @Override
        public void append(@NotNull DataOutput out) throws IOException {
          myValueExternalizer.save(out, valueRead);
        }
      }, readResult);

      myEnumerator.lockStorageWrite();
      try {
        myEnumerator.markDirty(true);

        if (myDirectlyStoreLongFileOffsetMode) {
          ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, newValueOffset);
        }
        else {
          updateValueId(id, newValueOffset, valueOffset, key, 0);
        }
        myLiveAndGarbageKeysCounter++;
        myReadCompactionGarbageSize += readResult.buffer.length;
      }
      finally {
        myEnumerator.unlockStorageWrite();
      }
    }
    return valueRead;
  }
private @Nullable Value doGet(Key key)