2 * SonarQube, open source software quality management tool.
3 * Copyright (C) 2008-2014 SonarSource
4 * mailto:contact AT sonarsource DOT com
6 * SonarQube is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * SonarQube is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 package org.sonar.server.benchmark;
23 import com.google.common.collect.Maps;
24 import org.apache.commons.io.FileUtils;
25 import org.apache.commons.lang.StringUtils;
26 import org.junit.Rule;
27 import org.junit.Test;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30 import org.sonar.server.es.EsClient;
31 import org.sonar.server.source.index.SourceLineDoc;
32 import org.sonar.server.source.index.SourceLineIndex;
33 import org.sonar.server.source.index.SourceLineIndexDefinition;
34 import org.sonar.server.source.index.SourceLineIndexer;
35 import org.sonar.server.source.index.SourceLineResultSetIterator;
36 import org.sonar.server.tester.ServerTester;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Timer;
41 import java.util.concurrent.atomic.AtomicLong;
43 import static org.assertj.core.api.Assertions.assertThat;
46 * Performance tests of the Elasticsearch index sourcelines
48 * <li>throughput of indexing of documents</li>
49 * <li>size of ES data directory</li>
50 * <li>time to request index</li>
53 public class SourceIndexBenchmarkTest {
55 private static final Logger LOGGER = LoggerFactory.getLogger("benchmarkSourceIndexing");
56 private static final long FILES = 1000L;
57 private static final int LINES_PER_FILE = 3220;
60 public ServerTester tester = new ServerTester();
63 public Benchmark benchmark = new Benchmark();
66 public void benchmark() throws Exception {
70 // execute some queries
74 private void benchmarkIndexing() {
75 LOGGER.info("Indexing source lines");
77 SourceIterator files = new SourceIterator(FILES, LINES_PER_FILE);
78 ProgressTask progressTask = new ProgressTask(LOGGER, "files of " + LINES_PER_FILE + " lines", files.count());
79 Timer timer = new Timer("SourceIndexer");
80 timer.schedule(progressTask, ProgressTask.PERIOD_MS, ProgressTask.PERIOD_MS);
82 long start = System.currentTimeMillis();
83 tester.get(SourceLineIndexer.class).index(files);
84 long end = System.currentTimeMillis();
87 long period = end - start;
88 long nbLines = files.count.get() * LINES_PER_FILE;
89 long throughputPerSecond = 1000L * nbLines / period;
90 LOGGER.info(String.format("%d lines indexed in %d ms (%d docs/second)", nbLines, period, throughputPerSecond));
91 benchmark.expectBetween("Throughput to index source lines", throughputPerSecond, 7500, 8000);
93 // be sure that physical files do not evolve during estimation of size
94 tester.get(EsClient.class).prepareOptimize(SourceLineIndexDefinition.INDEX).get();
95 long dirSize = FileUtils.sizeOfDirectory(tester.getEsServerHolder().getHomeDir());
96 LOGGER.info(String.format("ES dir: " + FileUtils.byteCountToDisplaySize(dirSize)));
97 benchmark.expectBetween("ES dir size (b)", dirSize, 103L * FileUtils.ONE_MB, 109L * FileUtils.ONE_MB);
100 private void benchmarkQueries() {
101 SourceLineIndex index = tester.get(SourceLineIndex.class);
102 for (int i = 1; i <= 100; i++) {
103 long start = System.currentTimeMillis();
104 List<SourceLineDoc> result = index.getLines("FILE" + i, 20, 150);
105 long end = System.currentTimeMillis();
106 assertThat(result).hasSize(131);
107 LOGGER.info("Request: {} docs in {} ms", result.size(), end - start);
112 private static class SourceIterator implements Iterator<SourceLineResultSetIterator.SourceFile> {
113 private final long nbFiles;
114 private final int nbLinesPerFile;
115 private int currentProject = 0;
116 private AtomicLong count = new AtomicLong(0L);
118 SourceIterator(long nbFiles, int nbLinesPerFile) {
119 this.nbFiles = nbFiles;
120 this.nbLinesPerFile = nbLinesPerFile;
123 public AtomicLong count() {
128 public boolean hasNext() {
129 return count.get() < nbFiles;
133 public SourceLineResultSetIterator.SourceFile next() {
134 String fileUuid = "FILE" + count.get();
135 SourceLineResultSetIterator.SourceFile file = new SourceLineResultSetIterator.SourceFile(fileUuid, System.currentTimeMillis());
136 for (int indexLine = 1; indexLine <= nbLinesPerFile; indexLine++) {
137 SourceLineDoc line = new SourceLineDoc(Maps.<String, Object>newHashMap());
138 line.setFileUuid(fileUuid);
139 line.setLine(indexLine);
140 line.setHighlighting(StringUtils.repeat("HIGHLIGHTING", 5));
141 line.setItConditions(4);
142 line.setItCoveredConditions(2);
143 line.setItLineHits(2);
144 line.setOverallConditions(8);
145 line.setOverallCoveredConditions(2);
146 line.setOverallLineHits(2);
147 line.setUtConditions(8);
148 line.setUtCoveredConditions(2);
149 line.setUtLineHits(2);
150 line.setProjectUuid("PROJECT" + currentProject);
151 line.setScmAuthor("a_guy");
152 line.setScmRevision("ABCDEFGHIJKL");
153 line.setSource(StringUtils.repeat("SOURCE", 10));
156 count.incrementAndGet();
157 if (count.get() % 500 == 0) {
164 public void remove() {
165 throw new UnsupportedOperationException();