Package com.intellij.ide.startup

Source Code of com.intellij.ide.startup.FileSystemSynchronizer$MyContentQueue

/*
* Copyright 2000-2007 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.intellij.ide.startup;

import com.intellij.ide.IdeBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.concurrent.ArrayBlockingQueue;

/**
* @author max
*/
public class FileSystemSynchronizer {
  private static final Logger LOG = Logger.getInstance("#com.intellij.ide.startup.FileSystemSynchronizer");

  private ArrayList<CacheUpdater> myUpdaters = new ArrayList<CacheUpdater>();
  private LinkedHashSet<VirtualFile> myFilesToUpdate = new LinkedHashSet<VirtualFile>();
  private Collection/*<VirtualFile>*/[] myUpdateSets;

  private boolean myIsCancelable = false;

  public void registerCacheUpdater(@NotNull CacheUpdater cacheUpdater) {
    myUpdaters.add(cacheUpdater);
  }

  public void setCancelable(boolean isCancelable) {
    myIsCancelable = isCancelable;
  }

  public void execute() {
    /*
    long time1 = System.currentTimeMillis();
    */

    if (!myIsCancelable) {
      ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
      if (indicator != null) {
        indicator.startNonCancelableSection();
      }
    }

    try {
      if (myUpdateSets == null) { // collectFilesToUpdate() was not executed before
        if (collectFilesToUpdate() == 0) return;
      }

      updateFiles();
    }
    catch (ProcessCanceledException e) {
      for (CacheUpdater updater : myUpdaters) {
        if (updater != null) {
          updater.canceled();
        }
      }
      throw e;
    }
    finally {
      if (!myIsCancelable) {
        ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
        if (indicator != null) {
          indicator.finishNonCancelableSection();
        }
      }
    }

    /*
    long time2 = System.currentTimeMillis();
    System.out.println("synchronizer.execute() in " + (time2 - time1) + " ms");
    */
  }

  public int collectFilesToUpdate() {
    ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
    if (indicator != null) {
      indicator.pushState();
      indicator.setText(IdeBundle.message("progress.scanning.files"));
    }

    myUpdateSets = new Collection[myUpdaters.size()];
    for (int i = 0; i < myUpdaters.size(); i++) {
      CacheUpdater updater = myUpdaters.get(i);
      try {
        VirtualFile[] updaterFiles = updater.queryNeededFiles();
        Collection<VirtualFile> localSet = new LinkedHashSet<VirtualFile>(Arrays.asList(updaterFiles));
        myFilesToUpdate.addAll(localSet);
        myUpdateSets[i] = localSet;
      }
      catch (ProcessCanceledException e) {
        throw e;
      }
      catch (Throwable e) {
        LOG.error(e);
        myUpdateSets[i] = new ArrayList();
      }
    }

    if (indicator != null) {
      indicator.popState();
    }

    if (myFilesToUpdate.isEmpty()) {
      updatingDone();
    }

    return myFilesToUpdate.size();
  }

  private void updateFiles() {
    final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
    if (indicator != null) {
      indicator.pushState();
      indicator.setText(IdeBundle.message("progress.parsing.files"));
    }

    int totalFiles = myFilesToUpdate.size();
    final MyContentQueue contentQueue = new MyContentQueue();

    final Runnable contentLoadingRunnable = new Runnable() {
      public void run() {
        try {
          for (VirtualFile file : myFilesToUpdate) {
            if (indicator != null) indicator.checkCanceled();
            contentQueue.put(file);
          }
        }
        catch (ProcessCanceledException e) {
          // Do nothing, exit the thread.
        }
        catch (InterruptedException e) {
          LOG.error(e);
        }
        finally {
          try {
            contentQueue.put(new FileContent(null));
          }
          catch (InterruptedException e) {
            LOG.error(e);
          }
        }
      }
    };

    ApplicationManager.getApplication().executeOnPooledThread(contentLoadingRunnable);

    int count = 0;
    while (true) {
      FileContent content = null;
      try {
        content = contentQueue.take();
      }
      catch (InterruptedException e) {
        LOG.error(e);
      }
      if (content == null) break;
      final VirtualFile file = content.getVirtualFile();
      if (file == null) break;
      if (indicator != null) {
        indicator.checkCanceled();
        indicator.setFraction((double)++count / totalFiles);
        indicator.setText2(file.getPresentableUrl());
      }
      for (int i = 0; i < myUpdaters.size(); i++) {
        CacheUpdater updater = myUpdaters.get(i);
        if (myUpdateSets[i].remove(file)) {
          try {
            updater.processFile(content);
          }
          catch (ProcessCanceledException e) {
            throw e;
          }
          catch (Throwable e) {
            LOG.error(e);
          }
          if (myUpdateSets[i].isEmpty()) {
            try {
              updater.updatingDone();
            }
            catch (ProcessCanceledException e) {
              throw e;
            }
            catch (Throwable e) {
              LOG.error(e);
            }
            myUpdaters.set(i, null);
          }
        }
      }
    }

    updatingDone();

    if (indicator != null) {
      indicator.popState();
    }
  }

  private void updatingDone() {
    for (CacheUpdater updater : myUpdaters) {
      try {
        if (updater != null) updater.updatingDone();
      }
      catch (ProcessCanceledException e) {
        throw e;
      }
      catch (Exception e) {
        LOG.error(e);
      }
    }

    dropUpdaters();
  }

  private void dropUpdaters() {
    myUpdaters.clear();
    myFilesToUpdate.clear();
    myUpdateSets = null;
  }

  @SuppressWarnings({"SynchronizeOnThis"})
  private static class MyContentQueue extends ArrayBlockingQueue<FileContent> {
    private long totalSize;
    private static final long SIZE_THRESHOLD = 1024*1024;

    public MyContentQueue() {
      super(256);
      totalSize = 0;
    }

    @SuppressWarnings({"MethodOverloadsMethodOfSuperclass"})
    public void put(VirtualFile file) throws InterruptedException {
      ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();

      FileContent content;
      synchronized (this) {
        content = new FileContent(file);
        if (file.isValid()) {
          try {
            if (content.getPhysicalLength() < SIZE_THRESHOLD) {
              while (totalSize > SIZE_THRESHOLD) {
                if (indicator != null) indicator.checkCanceled();
                wait(300);
              }

              totalSize += content.getPhysicalBytes().length;
            }
          }
          catch (IOException e) {
            content.setEmptyContent();
          }
          catch(ProcessCanceledException e) {
            throw e;
          }
          catch (Throwable e) {
            LOG.error(e);
          }
        }
        else {
          content.setEmptyContent();
        }
      }

      put(content);
    }


    public FileContent take() throws InterruptedException {
      final FileContent result = super.take();

      synchronized (this) {
        try {
          final VirtualFile file = result.getVirtualFile();
          if (file == null || !file.isValid() || result.getPhysicalLength() >= SIZE_THRESHOLD) return result;
          totalSize -= result.getPhysicalBytes().length;
        }
        catch (IOException e) {
          LOG.error(e);
        }
        finally {
          notifyAll();
        }
      }

      return result;
    }
  }
}
TOP

Related Classes of com.intellij.ide.startup.FileSystemSynchronizer$MyContentQueue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.