/*MUST be called under the WriteLock*/
    @NotNull
    private Map<Integer, SerializedStubTree> readOldData(final int key) throws StorageException {
      final Map<Integer, SerializedStubTree> result = new HashMap<Integer, SerializedStubTree>();

      IndexStorage<Integer, SerializedStubTree> indexStorage = myStorage;
      if (indexStorage instanceof MemoryIndexStorage) {
        final MemoryIndexStorage<Integer, SerializedStubTree> memIndexStorage =
            (MemoryIndexStorage<Integer, SerializedStubTree>) indexStorage;
        if (!memIndexStorage.isBufferingEnabled()) {
          // if buffering is not enabled, use backend storage to make sure
          // the returned stub tree contains no data corresponding to unsaved documents.
          // This will ensure that correct set of old keys is used for update
          indexStorage = memIndexStorage.getBackendStorage();
        }
      }
      try {
        final ValueContainer<SerializedStubTree> valueContainer = indexStorage.read(key);
        if (valueContainer.size() != 1) {
          LOG.assertTrue(valueContainer.size() == 0);
          return result;
        }

        result.put(key, valueContainer.getValueIterator().next());
        return result;
      } catch (RuntimeException e) {
        final Throwable cause = e.getCause();
        if (cause instanceof IOException) {
          throw new StorageException(cause);
        }
        throw e;
      }
    }
  @Override
  protected void doPut(Key key, ValueContainer<Value> container) throws IOException {
    synchronized (myEnumerator) {
      ChangeTrackingValueContainer<Value> valueContainer =
          (ChangeTrackingValueContainer<Value>) container;
      if (!valueContainer.needsCompacting()) {
        final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
        //noinspection IOResourceOpenedButNotSafelyClosed
        final DataOutputStream _out = new DataOutputStream(bytes);
        final TIntHashSet set = valueContainer.getInvalidated();
        if (set.size() > 0) {
          for (int inputId : set.toArray()) {
            ValueContainerExternalizer.saveInvalidateCommand(_out, inputId);
          }
        }
        final ValueContainer<Value> toRemove = valueContainer.getRemovedDelta();
        if (toRemove.size() > 0) {
          myValueContainerExternalizer.saveAsRemoved(_out, toRemove);
        }

        final ValueContainer<Value> toAppend = valueContainer.getAddedDelta();
        if (toAppend.size() > 0) {
          myValueContainerExternalizer.save(_out, toAppend);
        }

        appendData(
            key,
            new PersistentHashMap.ValueDataAppender() {
              public void append(final DataOutput out) throws IOException {
                out.write(bytes.getInternalBuffer(), 0, bytes.size());
              }
            });
      } else {
        // rewrite the value container for defragmentation
        super.doPut(key, valueContainer);
      }
    }
  }
    private void saveImpl(
        final DataOutput out, final ValueContainer<T> container, final boolean asRemovedData)
        throws IOException {
      DataInputOutputUtil.writeSINT(out, container.size());
      for (final Iterator<T> valueIterator = container.getValueIterator();
          valueIterator.hasNext(); ) {
        final T value = valueIterator.next();
        myExternalizer.save(out, value);

        final ValueContainer.IntIterator ids = container.getInputIdsIterator(value);
        if (ids != null) {
          DataInputOutputUtil.writeSINT(out, ids.size());
          while (ids.hasNext()) {
            final int id = ids.next();
            DataInputOutputUtil.writeSINT(out, asRemovedData ? -id : id);
          }
        } else {
          DataInputOutputUtil.writeSINT(out, 0);
        }
      }
    }