SonarQube6.2源码解析(四)

sonar ce 的启动过程


/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.ce.app;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.CheckForNull;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.ce.ComputeEngine;
import org.sonar.ce.ComputeEngineImpl;
import org.sonar.ce.container.ComputeEngineContainerImpl;
import org.sonar.process.MinimumViableSystem;
import org.sonar.process.Monitored;
import org.sonar.process.ProcessEntryPoint;
import org.sonar.process.Props;
import org.sonar.ce.log.CeProcessLogging;

import static com.google.common.base.Preconditions.checkState;
import static org.sonar.process.ProcessUtils.awaitTermination;

/**
 * The Compute Engine server which starts a daemon thread to run the {@link ComputeEngineImpl} when it's {@link #start()}
 * method is called.
 * <p>
 * This is the class to call to run a standalone {@link ComputeEngineImpl} (see {@link #main(String[])}).
 * </p>
 */
public class CeServer implements Monitored {
  private static final Logger LOG = Loggers.get(CeServer.class);

  private static final String CE_MAIN_THREAD_NAME = "ce-main";

  /**
   * Thread that currently is inside our await() method.
   */
  private AtomicReference<Thread> awaitThread = new AtomicReference<>();
  private volatile boolean stopAwait = false;

  private final StartupBarrier startupBarrier;
  private final ComputeEngine computeEngine;
  @CheckForNull
  private CeMainThread ceMainThread = null;

  @VisibleForTesting
  protected CeServer(StartupBarrier startupBarrier, ComputeEngine computeEngine, MinimumViableSystem mvs) {
    this.startupBarrier = startupBarrier;
    this.computeEngine = computeEngine;
    mvs
      .checkWritableTempDir()
      .checkRequiredJavaOptions(ImmutableMap.of("file.encoding", "UTF-8"));
  }

  @Override
  public void start() {
    checkState(ceMainThread == null, "start() can not be called twice");
    // start main thread
    ceMainThread = new CeMainThread();
    ceMainThread.start();
  }

  @Override
  public boolean isUp() {
    checkState(ceMainThread != null, "isUp() can not be called before start()");

    return ceMainThread.isStarted();
  }

  @Override
  public void awaitStop() {
    checkState(awaitThread.compareAndSet(null, Thread.currentThread()), "There can't be more than one thread waiting for the Compute Engine to stop");
    checkState(ceMainThread != null, "awaitStop() must not be called before start()");

    try {
      while (!stopAwait) {
        try {
          // wait for a quite long time but we will be interrupted if flag changes anyway
          Thread.sleep(10_000);
        } catch (InterruptedException e) {
          // continue and check the flag
        }
      }
    } finally {
      awaitThread = null;
    }
  }

  @Override
  public void stop() {
    if (ceMainThread != null) {
      // signal main Thread to stop
      ceMainThread.stopIt();
      awaitTermination(ceMainThread);
    }
  }

  /**
   * Can't be started as is. Needs to be bootstrapped by sonar-application
   */
  public static void main(String[] args) {
    ProcessEntryPoint entryPoint = ProcessEntryPoint.createForArguments(args);
    Props props = entryPoint.getProps();
    new CeProcessLogging().configure(props);
    CeServer server = new CeServer(
      new StartupBarrierFactory().create(entryPoint),
      new ComputeEngineImpl(props, new ComputeEngineContainerImpl()),
      new MinimumViableSystem());
    entryPoint.launch(server);
  }

  private class CeMainThread extends Thread {
    private static final int CHECK_FOR_STOP_DELAY = 50;
    private volatile boolean stop = false;
    private volatile boolean started = false;

    public CeMainThread() {
      super(CE_MAIN_THREAD_NAME);
    }

    @Override
    public void run() {
      boolean webServerOperational = startupBarrier.waitForOperational();
      if (!webServerOperational) {
        LOG.debug("Interrupted while waiting for WebServer to be operational. Assuming it will never be. Stopping.");
        // signal CE is done booting (obviously, since we are about to stop)
        this.started = true;
        // release thread (if any) in CeServer#awaitStop()
        stopAwait();
        return;
      }

      boolean startupSuccessful = attemptStartup();
      this.started = true;
      if (startupSuccessful) {
        // call below is blocking
        waitForStopSignal();
      } else {
        stopAwait();
      }
    }

    private boolean attemptStartup() {
      try {
        startup();
        return true;
      } catch (Throwable e) {
        LOG.error("Compute Engine startup failed", e);
        return false;
      }
    }

    private void startup() {
      LOG.info("Compute Engine starting up...");
      computeEngine.startup();
      LOG.info("Compute Engine is up");
    }

    private void waitForStopSignal() {
      while (!stop) {
        try {
          Thread.sleep(CHECK_FOR_STOP_DELAY);
        } catch (InterruptedException e) {
          // ignore the interruption itself, check the flag
        }
      }
      attemptShutdown();
    }

    private void attemptShutdown() {
      try {
        shutdown();
      } catch (Throwable e) {
        LOG.error("Compute Engine shutdown failed", e);
      } finally {
        // release thread waiting for CeServer
        stopAwait();
      }
    }

    private void shutdown() {
      LOG.info("Compute Engine shutting down...");
      computeEngine.shutdown();
    }

    public boolean isStarted() {
      return started;
    }

    public void stopIt() {
      // stop looping indefinitely
      this.stop = true;
      // interrupt current thread in case its waiting for WebServer
      interrupt();
    }

    private void stopAwait() {
      stopAwait = true;
      Thread t = awaitThread.get();
      if (t != null) {
        t.interrupt();
        try {
          t.join(1000);
        } catch (InterruptedException e) {
          // Ignored
        }
      }
    }
  }

}

调用的类ComputeEngineImpl->ComputeEngine:

/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.ce;

import org.sonar.ce.container.ComputeEngineContainer;
import org.sonar.process.Props;

import static com.google.common.base.Preconditions.checkState;

public class ComputeEngineImpl implements ComputeEngine {
  private final Props props;
  private final ComputeEngineContainer computeEngineContainer;

  private Status status = Status.INIT;

  public ComputeEngineImpl(Props props, ComputeEngineContainer computeEngineContainer) {
    this.props = props;
    this.computeEngineContainer = computeEngineContainer;
  }

  @Override
  public void startup() {
    checkState(this.status == Status.INIT, "startup() can not be called multiple times");
    try {
      this.status = Status.STARTING;
      this.computeEngineContainer.start(props);
    } finally {
      this.status = Status.STARTED;
    }
  }

  @Override
  public void shutdown() {
    checkStateAsShutdown(this.status);

    try {
      this.status = Status.STOPPING;
      this.computeEngineContainer.stop();
    } finally {
      this.status = Status.STOPPED;
    }
  }

  private static void checkStateAsShutdown(Status currentStatus) {
    checkState(currentStatus.ordinal() >= Status.STARTED.ordinal(), "shutdown() must not be called before startup()");
    checkState(currentStatus.ordinal() <= Status.STOPPING.ordinal(), "shutdown() can not be called multiple times");
  }

  private enum Status {
    INIT, STARTING, STARTED, STOPPING, STOPPED
  }
}

调用ComputeEngineContainerImpl->ComputeEngineContainer

public class ComputeEngineContainerImpl implements ComputeEngineContainer {

  @CheckForNull
  private ComponentContainer level1;
  @CheckForNull
  private ComponentContainer level4;

  @Override
  public ComputeEngineContainer start(Props props) {
    this.level1 = new ComponentContainer();
    this.level1
      .add(props.rawProperties())
      .add(level1Components())
      .add(toArray(CorePropertyDefinitions.all()))
      .add(toArray(ClusterProperties.definitions()));
    configureFromModules(this.level1);
    this.level1.startComponents();

    ComponentContainer level2 = this.level1.createChild();
    level2.add(level2Components());
    configureFromModules(level2);
    level2.startComponents();

    ComponentContainer level3 = level2.createChild();
    level3.add(level3Components());
    configureFromModules(level3);
    level3.startComponents();

    this.level4 = level3.createChild();
    this.level4.add(level4Components());
    configureFromModules(this.level4);
    ServerExtensionInstaller extensionInstaller = this.level4.getComponentByType(ServerExtensionInstaller.class);
    extensionInstaller.installExtensions(this.level4);
    this.level4.startComponents();

    startupTasks();

    return this;
  }

  private void startupTasks() {
    ComponentContainer startupLevel = this.level4.createChild();
    startupLevel.add(startupComponents());
    startupLevel.startComponents();
    // done in PlatformLevelStartup
    ServerLifecycleNotifier serverLifecycleNotifier = startupLevel.getComponentByType(ServerLifecycleNotifier.class);
    if (serverLifecycleNotifier != null) {
      serverLifecycleNotifier.notifyStart();
    }
    startupLevel.stopComponents();
  }

  @Override
  public ComputeEngineContainer stop() {
    this.level1.stopComponents();
    return this;
  }

  @VisibleForTesting
  protected ComponentContainer getComponentContainer() {
    return level4;
  }

  private static Object[] level1Components() {
    Version apiVersion = ApiVersion.load(System2.INSTANCE);
    return new Object[] {
      ThreadLocalSettings.class,
      new SonarQubeVersion(apiVersion),
      SonarRuntimeImpl.forSonarQube(ApiVersion.load(System2.INSTANCE), SonarQubeSide.COMPUTE_ENGINE),
      CeProcessLogging.class,
      UuidFactoryImpl.INSTANCE,
      ClusterImpl.class,
      LogbackHelper.class,
      DefaultDatabase.class,
      DatabaseChecker.class,
      // must instantiate deprecated class in 5.2 and only this one (and not its replacement)
      // to avoid having two SqlSessionFactory instances
      org.sonar.core.persistence.MyBatis.class,
      DatabaseServerCompatibility.class,
      DatabaseVersion.class,
      PurgeProfiler.class,
      ServerFileSystemImpl.class,
      new TempFolderProvider(),
      System2.INSTANCE,

      // user session
      CeUserSession.class,

      // DB
      DaoModule.class,
      ReadOnlyPropertiesDao.class,
      DbClient.class,

      // Elasticsearch
      EsSearchModule.class,

      // rules/qprofiles
      RuleIndex.class,
      ActiveRuleIndex.class,

      // issues
      IssueIndex.class,

      new OkHttpClientProvider()
    };
  }

  private static Object[] level2Components() {
    return new Object[] {
      DatabaseSettingLoader.class,
      DatabaseSettingsEnabler.class,
      UrlSettings.class,

      // add ReadOnlyPropertiesDao at level2 again so that it shadows PropertiesDao
      ReadOnlyPropertiesDao.class,
      DefaultServerUpgradeStatus.class,

      // plugins
      PluginClassloaderFactory.class,
      CePluginJarExploder.class,
      PluginLoader.class,
      CePluginRepository.class,
      InstalledPluginReferentialFactory.class,
      ComputeEngineExtensionInstaller.class,

      // depends on plugins
      DefaultI18n.class, // used by RuleI18nManager
      RuleI18nManager.class, // used by DebtRulesXMLImporter
      Durations.class, // used in Web Services and DebtCalculator
    };
  }

  private static Object[] level3Components() {
    return new Object[] {
      new StartupMetadataProvider(),
      ServerIdManager.class,
      UriReader.class,
      ServerImpl.class,
      DefaultOrganizationProviderImpl.class
    };
  }

  private static Object[] level4Components() {
    return new Object[] {
      ResourceTypes.class,
      DefaultResourceTypes.get(),
      Periods.class, // used by JRuby and EvaluationResultTextConverterImpl

      // quality profile
      ActiveRuleIndexer.class,
      XMLProfileParser.class,
      XMLProfileSerializer.class,
      AnnotationProfileParser.class,
      Rules.QProfiles.class,
      QProfileLookup.class,
      QProfileProjectOperations.class,

      // rule
      RuleIndexer.class,
      AnnotationRuleParser.class,
      XMLRuleParser.class,
      DefaultRuleFinder.class,
      DeprecatedRulesDefinitionLoader.class,
      CommonRuleDefinitionsImpl.class,
      RuleDefinitionsLoader.class,
      RulesDefinitionXmlLoader.class,

      // languages
      Languages.class, // used by CommonRuleDefinitionsImpl

      // measure
      CoreCustomMetrics.class,
      DefaultMetricFinder.class,

      // users
      DeprecatedUserFinder.class,
      DefaultUserFinder.class,
      UserIndexer.class,
      UserIndex.class,

      // permissions
      PermissionTemplateService.class,
      PermissionUpdater.class,
      UserPermissionChanger.class,
      GroupPermissionChanger.class,

      // components
      ComponentFinder.class, // used in ComponentService
      ComponentService.class, // used in ReportSubmitter
      NewAlerts.class,
      NewAlerts.newMetadata(),
      ComponentCleanerService.class,
      ProjectMeasuresIndexer.class,

      // views
      ViewIndexer.class,
      ViewIndex.class,

      // issues
      IssueIndexer.class,
      PermissionIndexer.class,
      IssueUpdater.class, // used in Web Services and CE's DebtCalculator
      FunctionExecutor.class, // used by IssueWorkflow
      IssueWorkflow.class, // used in Web Services and CE's DebtCalculator
      NewIssuesEmailTemplate.class,
      MyNewIssuesEmailTemplate.class,
      IssueChangesEmailTemplate.class,
      AlertsEmailTemplate.class,
      ChangesOnMyIssueNotificationDispatcher.class,
      ChangesOnMyIssueNotificationDispatcher.newMetadata(),
      NewIssuesNotificationDispatcher.class,
      NewIssuesNotificationDispatcher.newMetadata(),
      MyNewIssuesNotificationDispatcher.class,
      MyNewIssuesNotificationDispatcher.newMetadata(),
      DoNotFixNotificationDispatcher.class,
      DoNotFixNotificationDispatcher.newMetadata(),
      NewIssuesNotificationFactory.class, // used by SendIssueNotificationsStep
      EmailNotificationChannel.class,

      // technical debt
      DebtModelPluginRepository.class,
      DebtRulesXMLImporter.class,

      // Notifications
      EmailSettings.class,
      NotificationService.class,
      NotificationCenter.class,
      DefaultNotificationManager.class,

      // Tests
      TestIndexer.class,

      // System
      ServerLogging.class,

      // privileged plugins
      PrivilegedPluginsBootstraper.class,
      PrivilegedPluginsStopper.class,

      // Compute engine (must be after Views and Developer Cockpit)
      CeConfigurationModule.class,
      CeQueueModule.class,
      CeHttpModule.class,
      CeTaskCommonsModule.class,
      ProjectAnalysisTaskModule.class,
      CeTaskProcessorModule.class,

      InternalPropertiesImpl.class,
      ProjectSettingsFactory.class,
    };
  }

  private static Object[] startupComponents() {
    return new Object[] {
      LogServerId.class,
      ServerLifecycleNotifier.class,
      PurgeCeActivities.class,
    };
  }

  private static Object[] toArray(List<?> list) {
    return list.toArray(new Object[list.size()]);
  }

  private static void configureFromModules(ComponentContainer container) {
    List<Module> modules = container.getComponentsByType(Module.class);
    for (Module module : modules) {
      module.configure(container);
    }
  }
}
start方法调用startTask方法





猜你喜欢

转载自blog.csdn.net/lxlmycsdnfree/article/details/80094064