@Override
  @NotNull
  public byte[] contentsToByteArray(@NotNull final VirtualFile file, boolean cacheContent)
      throws IOException {
    InputStream contentStream = null;
    boolean reloadFromDelegate;
    boolean outdated;
    int fileId;
    synchronized (myInputLock) {
      fileId = getFileId(file);
      outdated = checkFlag(fileId, MUST_RELOAD_CONTENT) || FSRecords.getLength(fileId) == -1L;
      reloadFromDelegate = outdated || (contentStream = readContent(file)) == null;
    }

    if (reloadFromDelegate) {
      final NewVirtualFileSystem delegate = getDelegate(file);

      final byte[] content;
      if (outdated) {
        // in this case, file can have out-of-date length. so, update it first (it's needed for
        // correct contentsToByteArray() work)
        // see IDEA-90813 for possible bugs
        FSRecords.setLength(fileId, delegate.getLength(file));
        content = delegate.contentsToByteArray(file);
      } else {
        // a bit of optimization
        content = delegate.contentsToByteArray(file);
        FSRecords.setLength(fileId, content.length);
      }

      ApplicationEx application = (ApplicationEx) ApplicationManager.getApplication();
      // we should cache every local files content
      // because the local history feature is currently depends on this cache,
      // perforce offline mode as well
      if ((!delegate.isReadOnly()
              ||
              // do not cache archive content unless asked
              cacheContent && !application.isInternal() && !application.isUnitTestMode())
          && content.length <= PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD) {
        synchronized (myInputLock) {
          writeContent(file, new ByteSequence(content), delegate.isReadOnly());
          setFlag(file, MUST_RELOAD_CONTENT, false);
        }
      }

      return content;
    } else {
      try {
        final int length = (int) file.getLength();
        assert length >= 0 : file;
        return FileUtil.loadBytes(contentStream, length);
      } catch (IOException e) {
        throw FSRecords.handleError(e);
      }
    }
  }
  @NotNull
  private TIntHashSet calcForwardRefs(
      @NotNull final VirtualFile virtualFile, @NotNull final ProgressIndicator indicator)
      throws IndexNotReadyException, ApplicationUtil.CannotRunReadActionException {

    final TIntHashSet forward = new TIntHashSet();

    final PsiFile psiFile =
        ApplicationUtil.tryRunReadAction(
            () -> {
              if (myProject.isDisposed()) throw new ProcessCanceledException();
              if (fileCount.incrementAndGet() % 100 == 0) {
                PsiManager.getInstance(myProject).dropResolveCaches();
                try {
                  storage.flush();
                  log.flush();
                } catch (IOException e) {
                  LOG.error(e);
                }
              }

              return PsiManager.getInstance(myProject).findFile(virtualFile);
            });
    final int fileId = getAbsId(virtualFile);
    if (psiFile != null) {
      bytesSize.addAndGet(virtualFile.getLength());
      final Set<PsiElement> resolved = new THashSet<PsiElement>();
      ApplicationUtil.tryRunReadAction(
          new Runnable() {
            @Override
            public void run() {
              indicator.checkCanceled();

              if (psiFile instanceof PsiJavaFile) {
                psiFile.accept(
                    new JavaRecursiveElementWalkingVisitor() {
                      @Override
                      public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
                        indicator.checkCanceled();
                        resolveReference(reference, resolved);

                        super.visitReferenceElement(reference);
                      }
                    });
              } else {
                psiFile.accept(
                    new PsiRecursiveElementWalkingVisitor() {
                      @Override
                      public void visitElement(PsiElement element) {
                        for (PsiReference reference : element.getReferences()) {
                          indicator.checkCanceled();
                          resolveReference(reference, resolved);
                        }
                        super.visitElement(element);
                      }
                    });
              }

              indicator.checkCanceled();
              for (PsiElement element : resolved) {
                PsiFile file = element.getContainingFile();
                addIdAndSuperClasses(file, forward);
              }
            }
          });
    }

    forward.remove(fileId);
    return forward;
  }