]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6229 improve performance of ES indexing at startup
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 4 Mar 2015 15:29:33 +0000 (16:29 +0100)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 4 Mar 2015 15:32:44 +0000 (16:32 +0100)
19 files changed:
server/sonar-server/src/main/java/org/sonar/server/activity/index/ActivityIndexDefinition.java
server/sonar-server/src/main/java/org/sonar/server/activity/index/ActivityIndexer.java
server/sonar-server/src/main/java/org/sonar/server/es/BaseIndexer.java
server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java
server/sonar-server/src/main/java/org/sonar/server/es/IndexDefinitionHash.java
server/sonar-server/src/main/java/org/sonar/server/es/IndexDefinitions.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/es/IndexRegistry.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java
server/sonar-server/src/test/java/org/sonar/server/activity/ActivityServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/es/EsTester.java
server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java
server/sonar-server/src/test/java/org/sonar/server/es/IndexDefinitionHashTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb
server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/changelog.html.erb

index 9fd5756c51b338bc36022e5d3c8f2e5d2997749e..bac57c0423348485d7734e075dc8276fd361dcc6 100644 (file)
@@ -50,7 +50,6 @@ public class ActivityIndexDefinition implements IndexDefinition {
   @Override
   public void define(IndexDefinitionContext context) {
     NewIndex index = context.create(INDEX);
-    // refresh is always handled by ActivityIndexer
     index.getSettings().put("index.refresh_interval", "-1");
     index.getSettings().put("analysis.analyzer.default.type", "keyword");
 
index 2b4ba6e678e8d854bf64fc0275a520ffb225bba8..8a179f99fd5028f1f6f730e1f8c944affe8c48c5 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.activity.index;
 
-import org.elasticsearch.action.support.replication.ReplicationType;
 import org.elasticsearch.action.update.UpdateRequest;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.db.DbClient;
@@ -34,7 +33,6 @@ import java.util.Iterator;
  * Add to Elasticsearch index {@link org.sonar.server.activity.index.ActivityIndexDefinition} the rows of
  * db table ACTIVITIES that are not indexed yet
  * <p/>
- * TODO idea of improvement - index asynchronously with UpdateRequest#replicationType(ReplicationType.ASYNC)
  */
 public class ActivityIndexer extends BaseIndexer {
 
@@ -47,7 +45,7 @@ public class ActivityIndexer extends BaseIndexer {
 
   @Override
   protected long doIndex(long lastUpdatedAt) {
-    final BulkIndexer bulk = new BulkIndexer(esClient, ActivityIndexDefinition.INDEX);
+    BulkIndexer bulk = new BulkIndexer(esClient, ActivityIndexDefinition.INDEX);
     bulk.setLarge(lastUpdatedAt == 0L);
 
     DbSession dbSession = dbClient.openSession(false);
@@ -64,7 +62,7 @@ public class ActivityIndexer extends BaseIndexer {
   }
 
   public long index(Iterator<ActivityDoc> activities) {
-    final BulkIndexer bulk = new BulkIndexer(esClient, ActivityIndexDefinition.INDEX);
+    BulkIndexer bulk = new BulkIndexer(esClient, ActivityIndexDefinition.INDEX);
     return doIndex(bulk, activities);
   }
 
@@ -85,7 +83,6 @@ public class ActivityIndexer extends BaseIndexer {
   private UpdateRequest newUpsertRequest(ActivityDoc doc) {
     return new UpdateRequest(ActivityIndexDefinition.INDEX, ActivityIndexDefinition.TYPE, doc.getKey())
       .doc(doc.getFields())
-      .upsert(doc.getFields())
-      .replicationType(ReplicationType.ASYNC);
+      .upsert(doc.getFields());
   }
 }
index 5f88f181b3c5931fc3fdd7fef4ddb22d7dcc1484..5f5f564058d4b532eb4d294cb2c67547a080fd2b 100644 (file)
@@ -37,6 +37,17 @@ public abstract class BaseIndexer implements ServerComponent, Startable {
   protected final EsClient esClient;
   private volatile long lastUpdatedAt = 0L;
 
+  /**
+   * Indexers are disabled during server startup, to avoid too many consecutive refreshes of the same index
+   * An example is RegisterQualityProfiles. If {@link org.sonar.server.activity.index.ActivityIndexer} is enabled by
+   * default during startup, then each new activated rule generates a bulk request with a single document and then
+   * asks for index refresh -> big performance hit.
+   *
+   * Indices are populated and refreshed when all startup components have been executed. See
+   * {@link org.sonar.server.search.IndexSynchronizer}
+   */
+  private boolean enabled = false;
+
   protected BaseIndexer(EsClient client, long threadKeepAliveSeconds, String indexName, String typeName) {
     this.indexName = indexName;
     this.typeName = typeName;
@@ -46,26 +57,33 @@ public abstract class BaseIndexer implements ServerComponent, Startable {
   }
 
   public void index() {
-    final long requestedAt = System.currentTimeMillis();
-    Future submit = executor.submit(new Runnable() {
-      @Override
-      public void run() {
-        if (requestedAt > lastUpdatedAt) {
-          long l = doIndex(lastUpdatedAt);
-          // l can be 0 if no documents were indexed
-          lastUpdatedAt = Math.max(l, lastUpdatedAt);
+    if (enabled) {
+      final long requestedAt = System.currentTimeMillis();
+      Future submit = executor.submit(new Runnable() {
+        @Override
+        public void run() {
+          if (requestedAt > lastUpdatedAt) {
+            long l = doIndex(lastUpdatedAt);
+            // l can be 0 if no documents were indexed
+            lastUpdatedAt = Math.max(l, lastUpdatedAt);
+          }
         }
+      });
+      try {
+        Uninterruptibles.getUninterruptibly(submit);
+      } catch (ExecutionException e) {
+        Throwables.propagate(e);
       }
-    });
-    try {
-      Uninterruptibles.getUninterruptibly(submit);
-    } catch (ExecutionException e) {
-      Throwables.propagate(e);
     }
   }
 
   protected abstract long doIndex(long lastUpdatedAt);
 
+  public BaseIndexer setEnabled(boolean b) {
+    this.enabled = b;
+    return this;
+  }
+
   @Override
   public void start() {
     lastUpdatedAt = esClient.getLastUpdatedAt(indexName, typeName);
index 909fd00bcbaa6cc779c7f9802f79ed7f27f4d46e..1ef1d9ce3b804764dbd18944ce50fac3c4adf189 100644 (file)
@@ -45,17 +45,17 @@ public class IndexCreator implements ServerComponent, Startable {
   private static final String SETTING_HASH = "sonar_hash";
 
   private final EsClient client;
-  private final IndexRegistry registry;
+  private final IndexDefinitions definitions;
 
-  public IndexCreator(EsClient client, IndexRegistry registry) {
+  public IndexCreator(EsClient client, IndexDefinitions definitions) {
     this.client = client;
-    this.registry = registry;
+    this.definitions = definitions;
   }
 
   @Override
   public void start() {
     // create indices that do not exist or that have a new definition (different mapping, cluster enabled, ...)
-    for (IndexRegistry.Index index : registry.getIndices().values()) {
+    for (IndexDefinitions.Index index : definitions.getIndices().values()) {
       boolean exists = client.prepareIndicesExist(index.getName()).get().isExists();
       if (exists && needsToDeleteIndex(index)) {
         LOGGER.info(String.format("Delete index %s (settings changed)", index.getName()));
@@ -73,7 +73,7 @@ public class IndexCreator implements ServerComponent, Startable {
     // nothing to do
   }
 
-  private void createIndex(IndexRegistry.Index index) {
+  private void createIndex(IndexDefinitions.Index index) {
     LOGGER.info(String.format("Create index %s", index.getName()));
     ImmutableSettings.Builder settings = ImmutableSettings.builder();
     settings.put(index.getSettings());
@@ -88,7 +88,7 @@ public class IndexCreator implements ServerComponent, Startable {
     client.waitForStatus(ClusterHealthStatus.YELLOW);
 
     // create types
-    for (Map.Entry<String, IndexRegistry.IndexType> entry : index.getTypes().entrySet()) {
+    for (Map.Entry<String, IndexDefinitions.IndexType> entry : index.getTypes().entrySet()) {
       LOGGER.info(String.format("Create type %s/%s", index.getName(), entry.getKey()));
       PutMappingResponse mappingResponse = client.preparePutMapping(index.getName())
         .setType(entry.getKey())
@@ -106,7 +106,7 @@ public class IndexCreator implements ServerComponent, Startable {
     client.nativeClient().admin().indices().prepareDelete(indexName).get();
   }
 
-  private boolean needsToDeleteIndex(IndexRegistry.Index index) {
+  private boolean needsToDeleteIndex(IndexDefinitions.Index index) {
     boolean toBeDeleted = false;
     String hash = client.nativeClient().admin().indices().prepareGetSettings(index.getName()).get().getSetting(index.getName(), "index." + SETTING_HASH);
     if (hash != null) {
index 6df309abaa2c4bfbb7c8f8436326c8a7d08d39ec..6b2c208d022b2473bb8053d993c35bdab8b13c0e 100644 (file)
@@ -37,7 +37,7 @@ class IndexDefinitionHash {
 
   private static final char DELIMITER = ',';
 
-  String of(IndexRegistry.Index index) {
+  String of(IndexDefinitions.Index index) {
     return of(index.getSettings().getAsMap(), index.getTypes());
   }
 
@@ -50,8 +50,8 @@ class IndexDefinitionHash {
   }
 
   private void appendObject(StringBuilder sb, Object value) {
-    if (value instanceof IndexRegistry.IndexType) {
-      appendIndexType(sb, (IndexRegistry.IndexType) value);
+    if (value instanceof IndexDefinitions.IndexType) {
+      appendIndexType(sb, (IndexDefinitions.IndexType) value);
     } else if (value instanceof Map) {
       appendMap(sb, (Map) value);
     } else if (value instanceof Iterable) {
@@ -61,7 +61,7 @@ class IndexDefinitionHash {
     }
   }
 
-  private void appendIndexType(StringBuilder sb, IndexRegistry.IndexType type) {
+  private void appendIndexType(StringBuilder sb, IndexDefinitions.IndexType type) {
     appendMap(sb, type.getAttributes());
   }
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/IndexDefinitions.java b/server/sonar-server/src/main/java/org/sonar/server/es/IndexDefinitions.java
new file mode 100644 (file)
index 0000000..771f9b8
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.es;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.elasticsearch.common.settings.Settings;
+import org.picocontainer.Startable;
+import org.sonar.api.ServerComponent;
+
+import java.util.Map;
+
+/**
+ * This class collects definitions of all Elasticsearch indices during server startup
+ */
+public class IndexDefinitions implements ServerComponent, Startable {
+
+  /**
+   * Immutable copy of {@link org.sonar.server.es.NewIndex}
+   */
+  public static class Index {
+    private final String name;
+    private final Settings settings;
+    private final Map<String, IndexType> types;
+
+    Index(NewIndex newIndex) {
+      this.name = newIndex.getName();
+      this.settings = newIndex.getSettings().build();
+      ImmutableMap.Builder<String, IndexType> builder = ImmutableMap.builder();
+      for (NewIndex.NewIndexType newIndexType : newIndex.getTypes().values()) {
+        IndexType type = new IndexType(newIndexType);
+        builder.put(type.getName(), type);
+      }
+      this.types = builder.build();
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public Settings getSettings() {
+      return settings;
+    }
+
+    public Map<String, IndexType> getTypes() {
+      return types;
+    }
+  }
+
+  /**
+   * Immutable copy of {@link org.sonar.server.es.NewIndex.NewIndexType}
+   */
+  public static class IndexType {
+    private final String name;
+    private final Map<String, Object> attributes;
+
+    private IndexType(NewIndex.NewIndexType newType) {
+      this.name = newType.getName();
+      this.attributes = ImmutableMap.copyOf(newType.getAttributes());
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public Map<String, Object> getAttributes() {
+      return attributes;
+    }
+  }
+
+  private final Map<String, Index> byKey = Maps.newHashMap();
+  private final IndexDefinition[] defs;
+
+  public IndexDefinitions(IndexDefinition[] defs) {
+    this.defs = defs;
+  }
+
+  public Map<String, Index> getIndices() {
+    return byKey;
+  }
+
+  @Override
+  public void start() {
+    // collect definitions
+    IndexDefinition.IndexDefinitionContext context = new IndexDefinition.IndexDefinitionContext();
+    for (IndexDefinition definition : defs) {
+      definition.define(context);
+    }
+
+    for (Map.Entry<String, NewIndex> entry : context.getIndices().entrySet()) {
+      byKey.put(entry.getKey(), new Index(entry.getValue()));
+    }
+  }
+
+  @Override
+  public void stop() {
+    // nothing to do
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/IndexRegistry.java b/server/sonar-server/src/main/java/org/sonar/server/es/IndexRegistry.java
deleted file mode 100644 (file)
index 9728300..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.server.es;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import org.elasticsearch.common.settings.Settings;
-import org.picocontainer.Startable;
-import org.sonar.api.ServerComponent;
-
-import java.util.Map;
-
-/**
- * This class collects definitions of all Elasticsearch indices during server startup
- */
-public class IndexRegistry implements ServerComponent, Startable {
-
-  /**
-   * Immutable copy of {@link org.sonar.server.es.NewIndex}
-   */
-  public static class Index {
-    private final String name;
-    private final Settings settings;
-    private final Map<String, IndexType> types;
-
-    Index(NewIndex newIndex) {
-      this.name = newIndex.getName();
-      this.settings = newIndex.getSettings().build();
-      ImmutableMap.Builder<String, IndexType> builder = ImmutableMap.builder();
-      for (NewIndex.NewIndexType newIndexType : newIndex.getTypes().values()) {
-        IndexType type = new IndexType(newIndexType);
-        builder.put(type.getName(), type);
-      }
-      this.types = builder.build();
-    }
-
-    public String getName() {
-      return name;
-    }
-
-    public Settings getSettings() {
-      return settings;
-    }
-
-    public Map<String, IndexType> getTypes() {
-      return types;
-    }
-  }
-
-  /**
-   * Immutable copy of {@link org.sonar.server.es.NewIndex.NewIndexType}
-   */
-  public static class IndexType {
-    private final String name;
-    private final Map<String, Object> attributes;
-
-    private IndexType(NewIndex.NewIndexType newType) {
-      this.name = newType.getName();
-      this.attributes = ImmutableMap.copyOf(newType.getAttributes());
-    }
-
-    public String getName() {
-      return name;
-    }
-
-    public Map<String, Object> getAttributes() {
-      return attributes;
-    }
-  }
-
-  private final Map<String, Index> byKey = Maps.newHashMap();
-  private final IndexDefinition[] defs;
-
-  public IndexRegistry(IndexDefinition[] defs) {
-    this.defs = defs;
-  }
-
-  public Map<String, Index> getIndices() {
-    return byKey;
-  }
-
-  @Override
-  public void start() {
-    // collect definitions
-    IndexDefinition.IndexDefinitionContext context = new IndexDefinition.IndexDefinitionContext();
-    for (IndexDefinition definition : defs) {
-      definition.define(context);
-    }
-
-    for (Map.Entry<String, NewIndex> entry : context.getIndices().entrySet()) {
-      byKey.put(entry.getKey(), new Index(entry.getValue()));
-    }
-  }
-
-  @Override
-  public void stop() {
-    // nothing to do
-  }
-}
index dd409d3e8aef78bcad4243525275a89a2094fc45..66c8d2ff0ecf1d024bcdc0adbbcacb1a259f3091 100644 (file)
@@ -136,7 +136,7 @@ import org.sonar.server.duplication.ws.DuplicationsParser;
 import org.sonar.server.duplication.ws.DuplicationsWs;
 import org.sonar.server.es.EsClient;
 import org.sonar.server.es.IndexCreator;
-import org.sonar.server.es.IndexRegistry;
+import org.sonar.server.es.IndexDefinitions;
 import org.sonar.server.issue.ActionService;
 import org.sonar.server.issue.AddTagsAction;
 import org.sonar.server.issue.AssignAction;
@@ -485,7 +485,7 @@ class ServerComponents {
     pico.addSingleton(Periods.class);
     pico.addSingleton(ServerWs.class);
     pico.addSingleton(BackendCleanup.class);
-    pico.addSingleton(IndexRegistry.class);
+    pico.addSingleton(IndexDefinitions.class);
     pico.addSingleton(IndexCreator.class);
 
     // Activity
@@ -847,8 +847,8 @@ class ServerComponents {
     DoPrivileged.execute(new DoPrivileged.Task() {
       @Override
       protected void doPrivileged() {
-        startupContainer.getComponentsByType(IndexSynchronizer.class).get(0).execute();
         startupContainer.startComponents();
+        startupContainer.getComponentByType(IndexSynchronizer.class).execute();
         startupContainer.getComponentByType(ServerLifecycleNotifier.class).notifyStart();
       }
     });
index b4499a4d20c8881226edfa59e97288fa23c3606b..6e0a4dca98afa41e3edf9436487a7b892a6c4a2a 100644 (file)
@@ -49,6 +49,11 @@ public class IndexSynchronizer {
   private final ViewIndexer viewIndexer;
   private final ActivityIndexer activityIndexer;
 
+  /**
+   * Limitation - {@link org.sonar.server.es.BaseIndexer} are not injected through an array or a collection
+   * because we need {@link org.sonar.server.issue.index.IssueAuthorizationIndexer} to be executed before
+   * {@link org.sonar.server.issue.index.IssueIndexer}
+   */
   public IndexSynchronizer(DbClient db, IndexClient index, SourceLineIndexer sourceLineIndexer,
                            IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer,
                            UserIndexer userIndexer, ViewIndexer viewIndexer, ActivityIndexer activityIndexer) {
@@ -73,30 +78,29 @@ public class IndexSynchronizer {
     }
 
     LOG.info("Index activities");
-    activityIndexer.index();
+    activityIndexer.setEnabled(true).index();
 
     LOG.info("Index issues");
-    issueAuthorizationIndexer.index();
-    issueIndexer.index();
+    issueAuthorizationIndexer.setEnabled(true).index();
+    issueIndexer.setEnabled(true).index();
 
-    LOG.info("Index source files");
-    sourceLineIndexer.index();
+    LOG.info("Index source lines");
+    sourceLineIndexer.setEnabled(true).index();
 
     LOG.info("Index users");
-    userIndexer.index();
+    userIndexer.setEnabled(true).index();
 
     LOG.info("Index views");
-    viewIndexer.index();
+    viewIndexer.setEnabled(true).index();
   }
 
   void synchronize(DbSession session, Dao dao, Index index) {
     long count = index.getIndexStat().getDocumentCount();
     Date lastSynch = index.getLastSynchronization();
+    LOG.info("Index {}s", index.getIndexType());
     if (count <= 0) {
-      LOG.info("Index {}s", index.getIndexType());
       dao.synchronizeAfter(session);
     } else {
-      LOG.info("Index {}s for updates after {}", index.getIndexType(), lastSynch);
       dao.synchronizeAfter(session, lastSynch);
     }
   }
index 14807cdde9c7f36201411bebb8449083cb4330c3..d12d072f1f38ba12ac167c5678576e5274c9773e 100644 (file)
@@ -57,7 +57,10 @@ public class ActivityServiceTest {
     ActivityDao activityDao = new ActivityDao(db.myBatis(), system);
     IssueDao issueDao = new IssueDao(db.myBatis());
     DbClient dbClient = new DbClient(db.database(), db.myBatis(), issueDao, activityDao);
-    service = new ActivityService(dbClient, new ActivityIndexer(dbClient, es.client()));
+    ActivityIndexer indexer = new ActivityIndexer(dbClient, es.client());
+    // indexers are disabled by default
+    indexer.setEnabled(true);
+    service = new ActivityService(dbClient, indexer);
   }
 
   @Test
index 09aaf8cd403ba2b1f99f0deff010bec45771599e..5c49de4aef1f7ef7cb0e4ca75e40138bf5a9c061 100644 (file)
@@ -103,7 +103,7 @@ public class EsTester extends ExternalResource {
       ComponentContainer container = new ComponentContainer();
       container.addSingletons(definitions);
       container.addSingleton(client);
-      container.addSingleton(IndexRegistry.class);
+      container.addSingleton(IndexDefinitions.class);
       container.addSingleton(IndexCreator.class);
       container.startComponents();
     }
index 06ba9d18d4a2410bfdc1d7f4f66f1f2c648379e1..ac55e4e4c53d7e9450cab8658ed4f638fc79ba74 100644 (file)
@@ -41,7 +41,7 @@ public class IndexCreatorTest {
   public void create_index() throws Exception {
     assertThat(mappings()).isEmpty();
 
-    IndexRegistry registry = new IndexRegistry(new IndexDefinition[] {new FakeIndexDefinition()});
+    IndexDefinitions registry = new IndexDefinitions(new IndexDefinition[] {new FakeIndexDefinition()});
     registry.start();
     IndexCreator creator = new IndexCreator(es.client(), registry);
     creator.start();
@@ -66,7 +66,7 @@ public class IndexCreatorTest {
     assertThat(mappings()).isEmpty();
 
     // v1
-    IndexRegistry registry = new IndexRegistry(new IndexDefinition[] {new FakeIndexDefinition()});
+    IndexDefinitions registry = new IndexDefinitions(new IndexDefinition[] {new FakeIndexDefinition()});
     registry.start();
     IndexCreator creator = new IndexCreator(es.client(), registry);
     creator.start();
@@ -75,7 +75,7 @@ public class IndexCreatorTest {
     assertThat(hashV1).isNotEmpty();
 
     // v2
-    registry = new IndexRegistry(new IndexDefinition[] {new FakeIndexDefinitionV2()});
+    registry = new IndexDefinitions(new IndexDefinition[] {new FakeIndexDefinitionV2()});
     registry.start();
     creator = new IndexCreator(es.client(), registry);
     creator.start();
index 958247d87a5fe4661de23f9404286c7fb95863e6..20cff8f8548191953b08ce5ce88fe6843eb29984 100644 (file)
@@ -29,7 +29,7 @@ public class IndexDefinitionHashTest {
 
   @Test
   public void of() throws Exception {
-    IndexRegistry.Index indexV1 = new IndexRegistry.Index(createIndex());
+    IndexDefinitions.Index indexV1 = new IndexDefinitions.Index(createIndex());
     String hashV1 = new IndexDefinitionHash().of(indexV1);
     assertThat(hashV1).isNotEmpty();
     // always the same
@@ -37,7 +37,7 @@ public class IndexDefinitionHashTest {
 
     NewIndex newIndexV2 = createIndex();
     newIndexV2.getTypes().get("fake").createIntegerField("max");
-    String hashV2 = new IndexDefinitionHash().of(new IndexRegistry.Index(newIndexV2));
+    String hashV2 = new IndexDefinitionHash().of(new IndexDefinitions.Index(newIndexV2));
     assertThat(hashV2).isNotEmpty().isNotEqualTo(hashV1);
   }
 
index cc87af2c9a8ca8f48b00a838c38695e2127d6396..f32df80aa98738ff41e275bd568b025f7ec9c5c1 100644 (file)
@@ -57,6 +57,15 @@ public class IssueIndexerTest {
     assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE)).isEqualTo(0L);
   }
 
+  @Test
+  public void index_nothing_if_disabled() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "index.xml");
+
+    createIndexer().setEnabled(false).index();
+
+    assertThat(esTester.countDocuments("issues", "issue")).isEqualTo(0);
+  }
+
   @Test
   public void index() throws Exception {
     dbTester.prepareDbUnit(getClass(), "index.xml");
@@ -82,6 +91,8 @@ public class IssueIndexerTest {
   }
 
   private IssueIndexer createIndexer() {
-    return new IssueIndexer(new DbClient(dbTester.database(), dbTester.myBatis()), esTester.client());
+    IssueIndexer indexer = new IssueIndexer(new DbClient(dbTester.database(), dbTester.myBatis()), esTester.client());
+    indexer.setEnabled(true);
+    return indexer;
   }
 }
index 5ba75c5f6eceb00cf6fa7443f04d85df634f2643..a9b87db14d5dde7430b375fdb08c482b4796363b 100644 (file)
@@ -68,6 +68,7 @@ public class SourceLineIndexerTest {
     es.truncateIndices();
     db.truncateTables();
     indexer = new SourceLineIndexer(new DbClient(db.database(), db.myBatis()), es.client());
+    indexer.setEnabled(true);
   }
 
   @Test
index fdbcefb81ac3eceb84fb201229387514e905e696..812b703252aa580ce689829bbda231df82ea540f 100644 (file)
@@ -74,7 +74,17 @@ public class UserIndexerTest {
     assertThat(doc.updatedAt()).isEqualTo(1500000000000L);
   }
 
+  @Test
+  public void do_nothing_if_disabled() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "index.xml");
+
+    createIndexer().setEnabled(false).index();
+    assertThat(esTester.countDocuments("users", "user")).isEqualTo(0);
+  }
+
   private UserIndexer createIndexer() {
-    return new UserIndexer(new DbClient(dbTester.database(), dbTester.myBatis()), esTester.client());
+    UserIndexer indexer = new UserIndexer(new DbClient(dbTester.database(), dbTester.myBatis()), esTester.client());
+    indexer.setEnabled(true);
+    return indexer;
   }
 }
index b809a46922ece8e5971132bc432b1a8e863fcd8b..9656c19994859e1d32c605d6125c74b2d341eafa 100644 (file)
@@ -55,6 +55,7 @@ public class ViewIndexerTest {
     dbTester.truncateTables();
     esTester.truncateIndices();
     indexer = new ViewIndexer(new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao()), esTester.client());
+    indexer.setEnabled(true);
   }
 
   @Test
index 2b107edfefb6838cf4a618763fb0044b05acb34d..79b88b22bb05f776368caeba3b999829fc3e3bb4 100644 (file)
@@ -268,6 +268,7 @@ class ProfilesController < ApplicationController
     require_parameters 'key'
 
     @profile = Internal.qprofile_loader.getByKey(params[:key])
+    not_found('Quality profile does not exist') unless @profile
     search = {'profileKey' => @profile.key().to_s, 'since' => params[:since], 'to' => params[:to], 'p' => params[:p]}
     result = Internal.component(Java::OrgSonarServerActivity::RubyQProfileActivityService.java_class).search(search)
     @changes = result.activities
index 035bf52d2d559cb5c67123e264c6461865aec273..f807ae791c2b7f6491e1ab27e403081a34eefbdb 100644 (file)
         %>
         <tr class="<%= cycle('even', 'odd') -%>">
           <%
-             action = change.action()
+             action = change.getAction()
              action_message = message('quality_profiles.changelog.' + action.downcase) if action
 
              if change.authorName() && !change.authorName().empty?()
                author = change.authorName()
-             elsif change.login() && !change.login().empty?()
-               author = change.login()
+             elsif change.login() && !change.getLogin().empty?()
+               author = change.getLogin()
              else
                author = 'System'
              end
              rule = change.ruleName() ? change.ruleName() : change.ruleKey()
           %>
-          <td valign="top" width="1%" nowrap><%= Internal.i18n.formatDateTime(change.time()) -%></td>
+          <td valign="top" width="1%" nowrap><%= Internal.i18n.formatDateTime(change.getCreatedAt()) -%></td>
           <td valign="top" width="1%" nowrap><%= author %></td>
           <td valign="top" width="1%" nowrap><%= action_message %></td>
           <td valign="top"><%= rule %></td>