private void saveFsState(File dataStorageRoot, BuildFSState state) {
    final ProjectDescriptor pd = myProjectDescriptor;
    final File file = new File(dataStorageRoot, FS_STATE_FILE);
    try {
      final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
      final DataOutputStream out = new DataOutputStream(bytes);
      try {
        out.writeInt(FSState.VERSION);
        out.writeLong(myLastEventOrdinal);
        boolean hasWorkToDoWithModules = false;
        for (JpsModule module : pd.getProject().getModules()) {
          for (JavaModuleBuildTargetType type : JavaModuleBuildTargetType.ALL_TYPES) {
            if (state.hasWorkToDo(new ModuleBuildTarget(module, type))) {
              hasWorkToDoWithModules = true;
              break;
            }
          }
          if (hasWorkToDoWithModules) {
            break;
          }
        }
        out.writeBoolean(hasWorkToDoWithModules);
        state.save(out);
      } finally {
        out.close();
      }

      saveOnDisk(bytes, file);
    } catch (Throwable e) {
      LOG.error(e);
      FileUtil.delete(file);
    }
  }
  private void runBuild(final MessageHandler msgHandler, CanceledStatus cs) throws Throwable {
    final File dataStorageRoot = Utils.getDataStorageRoot(myProjectPath);
    if (dataStorageRoot == null) {
      msgHandler.processMessage(
          new CompilerMessage(
              "build",
              BuildMessage.Kind.ERROR,
              "Cannot determine build data storage root for project " + myProjectPath));
      return;
    }
    if (!dataStorageRoot.exists()) {
      // invoked the very first time for this project. Force full rebuild
      myBuildType = BuildType.PROJECT_REBUILD;
    }

    final DataInputStream fsStateStream = createFSDataStream(dataStorageRoot);

    if (fsStateStream != null) {
      // optimization: check whether we can skip the build
      final boolean hasWorkToDoWithModules = fsStateStream.readBoolean();
      if (myBuildType == BuildType.MAKE
          && !hasWorkToDoWithModules
          && scopeContainsModulesOnly(myBuildRunner.getScopes())
          && !containsChanges(myInitialFSDelta)) {
        updateFsStateOnDisk(dataStorageRoot, fsStateStream, myInitialFSDelta.getOrdinal());
        return;
      }
    }

    final BuildFSState fsState = new BuildFSState(false);
    try {
      final ProjectDescriptor pd = myBuildRunner.load(msgHandler, dataStorageRoot, fsState);
      myProjectDescriptor = pd;
      if (fsStateStream != null) {
        try {
          try {
            fsState.load(fsStateStream, pd.getModel(), pd.getBuildRootIndex());
            applyFSEvent(pd, myInitialFSDelta);
          } finally {
            fsStateStream.close();
          }
        } catch (Throwable e) {
          LOG.error(e);
          fsState.clearAll();
        }
      }
      myLastEventOrdinal = myInitialFSDelta != null ? myInitialFSDelta.getOrdinal() : 0L;

      // free memory
      myInitialFSDelta = null;
      // ensure events from controller are processed after FSState initialization
      myEventsProcessor.startProcessing();

      myBuildRunner.runBuild(pd, cs, myConstantSearch, msgHandler, myBuildType);
    } finally {
      saveData(fsState, dataStorageRoot);
    }
  }
 public static void processFilesToRecompile(
     final CompileContext context,
     final ModuleChunk chunk,
     final Condition<JpsModule> moduleFilter,
     final FileProcessor processor)
     throws IOException {
   final BuildFSState fsState = context.getProjectDescriptor().fsState;
   for (ModuleBuildTarget target : chunk.getTargets()) {
     if (moduleFilter.value(target.getModule())) {
       fsState.processFilesToRecompile(context, target, processor);
     }
   }
 }