Merge "Merge branch 'stable-2.14' into stable-2.15" into stable-2.15
This commit is contained in:
		@@ -63,6 +63,7 @@ junit_tests(
 | 
			
		||||
        "//gerrit-server:query_tests_code",
 | 
			
		||||
        "//gerrit-server:server",
 | 
			
		||||
        "//gerrit-server:testutil",
 | 
			
		||||
        "//lib:truth",
 | 
			
		||||
        "//lib/guice",
 | 
			
		||||
        "//lib/httpcomponents:httpcore",
 | 
			
		||||
        "//lib/jgit/org.eclipse.jgit:jgit",
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,6 @@ public class ElasticIndexModule extends AbstractIndexModule {
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  protected Class<? extends VersionManager> getVersionManager() {
 | 
			
		||||
    return ElasticVersionManager.class;
 | 
			
		||||
    return ElasticIndexVersionManager.class;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,14 +32,14 @@ import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
@Singleton
 | 
			
		||||
public class ElasticVersionManager extends VersionManager {
 | 
			
		||||
  private static final Logger log = LoggerFactory.getLogger(ElasticVersionManager.class);
 | 
			
		||||
public class ElasticIndexVersionManager extends VersionManager {
 | 
			
		||||
  private static final Logger log = LoggerFactory.getLogger(ElasticIndexVersionManager.class);
 | 
			
		||||
 | 
			
		||||
  private final String prefix;
 | 
			
		||||
  private final ElasticIndexVersionDiscovery versionDiscovery;
 | 
			
		||||
 | 
			
		||||
  @Inject
 | 
			
		||||
  ElasticVersionManager(
 | 
			
		||||
  ElasticIndexVersionManager(
 | 
			
		||||
      ElasticConfiguration cfg,
 | 
			
		||||
      SitePaths sitePaths,
 | 
			
		||||
      DynamicSet<OnlineUpgradeListener> listeners,
 | 
			
		||||
@@ -26,7 +26,7 @@ class ElasticMapping {
 | 
			
		||||
    for (FieldDef<?, ?> field : schema.getFields().values()) {
 | 
			
		||||
      String name = field.getName();
 | 
			
		||||
      FieldType<?> fieldType = field.getType();
 | 
			
		||||
      if (fieldType == FieldType.EXACT) {
 | 
			
		||||
      if (fieldType == FieldType.EXACT || fieldType == FieldType.KEYWORD) {
 | 
			
		||||
        mapping.addExactField(name);
 | 
			
		||||
      } else if (fieldType == FieldType.TIMESTAMP) {
 | 
			
		||||
        mapping.addTimestamp(name);
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ public class ElasticQueryBuilder {
 | 
			
		||||
      return intRangeQuery(p);
 | 
			
		||||
    } else if (type == FieldType.TIMESTAMP) {
 | 
			
		||||
      return timestampQuery(p);
 | 
			
		||||
    } else if (type == FieldType.EXACT) {
 | 
			
		||||
    } else if (type == FieldType.EXACT || type == FieldType.KEYWORD) {
 | 
			
		||||
      return exactQuery(p);
 | 
			
		||||
    } else if (type == FieldType.PREFIX) {
 | 
			
		||||
      return QueryBuilders.matchPhrasePrefixQuery(name, value);
 | 
			
		||||
 
 | 
			
		||||
@@ -67,8 +67,8 @@ class ElasticRestClientProvider implements Provider<RestClient>, LifecycleListen
 | 
			
		||||
      synchronized (this) {
 | 
			
		||||
        if (client == null) {
 | 
			
		||||
          client = build();
 | 
			
		||||
          String version = getVersion();
 | 
			
		||||
          log.info("Connected to Elasticsearch version {}", version);
 | 
			
		||||
          ElasticVersion version = getVersion();
 | 
			
		||||
          log.info("Elasticsearch integration version {}", version);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@@ -102,20 +102,23 @@ class ElasticRestClientProvider implements Provider<RestClient>, LifecycleListen
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private String getVersion() throws ElasticException {
 | 
			
		||||
  private ElasticVersion getVersion() throws ElasticException {
 | 
			
		||||
    try {
 | 
			
		||||
      Response response = client.performRequest("GET", "");
 | 
			
		||||
      StatusLine statusLine = response.getStatusLine();
 | 
			
		||||
      if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
 | 
			
		||||
        throw new FailedToGetVersion(statusLine);
 | 
			
		||||
      }
 | 
			
		||||
      return new JsonParser()
 | 
			
		||||
          .parse(AbstractElasticIndex.getContent(response))
 | 
			
		||||
          .getAsJsonObject()
 | 
			
		||||
          .get("version")
 | 
			
		||||
          .getAsJsonObject()
 | 
			
		||||
          .get("number")
 | 
			
		||||
          .getAsString();
 | 
			
		||||
      String version =
 | 
			
		||||
          new JsonParser()
 | 
			
		||||
              .parse(AbstractElasticIndex.getContent(response))
 | 
			
		||||
              .getAsJsonObject()
 | 
			
		||||
              .get("version")
 | 
			
		||||
              .getAsJsonObject()
 | 
			
		||||
              .get("number")
 | 
			
		||||
              .getAsString();
 | 
			
		||||
      log.info("Connected to Elasticsearch version {}", version);
 | 
			
		||||
      return ElasticVersion.forVersion(version);
 | 
			
		||||
    } catch (IOException e) {
 | 
			
		||||
      throw new FailedToGetVersion(e);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,60 @@
 | 
			
		||||
// Copyright (C) 2018 The Android Open Source Project
 | 
			
		||||
//
 | 
			
		||||
// 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.google.gerrit.elasticsearch;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Joiner;
 | 
			
		||||
import java.util.regex.Pattern;
 | 
			
		||||
 | 
			
		||||
public enum ElasticVersion {
 | 
			
		||||
  V2_4("2.4.*"),
 | 
			
		||||
  V5_6("5.6.*"),
 | 
			
		||||
  V6_2("6.2.*");
 | 
			
		||||
 | 
			
		||||
  private final String version;
 | 
			
		||||
  private final Pattern pattern;
 | 
			
		||||
 | 
			
		||||
  private ElasticVersion(String version) {
 | 
			
		||||
    this.version = version;
 | 
			
		||||
    this.pattern = Pattern.compile(version);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static class InvalidVersion extends ElasticException {
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    InvalidVersion(String version) {
 | 
			
		||||
      super(
 | 
			
		||||
          String.format(
 | 
			
		||||
              "Invalid version: [%s]. Supported versions: %s", version, supportedVersions()));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static ElasticVersion forVersion(String version) throws InvalidVersion {
 | 
			
		||||
    for (ElasticVersion value : ElasticVersion.values()) {
 | 
			
		||||
      if (value.pattern.matcher(version).matches()) {
 | 
			
		||||
        return value;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    throw new InvalidVersion(version);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static String supportedVersions() {
 | 
			
		||||
    return Joiner.on(", ").join(ElasticVersion.values());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public String toString() {
 | 
			
		||||
    return version;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
package com.google.gerrit.elasticsearch;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableSet;
 | 
			
		||||
import com.google.gerrit.elasticsearch.ElasticVersion;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import org.apache.http.HttpHost;
 | 
			
		||||
import org.junit.internal.AssumptionViolatedException;
 | 
			
		||||
@@ -24,13 +25,7 @@ import org.testcontainers.containers.GenericContainer;
 | 
			
		||||
public class ElasticContainer<SELF extends ElasticContainer<SELF>> extends GenericContainer<SELF> {
 | 
			
		||||
  private static final int ELASTICSEARCH_DEFAULT_PORT = 9200;
 | 
			
		||||
 | 
			
		||||
  public enum Version {
 | 
			
		||||
    V2,
 | 
			
		||||
    V5,
 | 
			
		||||
    V6
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static ElasticContainer<?> createAndStart(Version version) {
 | 
			
		||||
  public static ElasticContainer<?> createAndStart(ElasticVersion version) {
 | 
			
		||||
    // Assumption violation is not natively supported by Testcontainers.
 | 
			
		||||
    // See https://github.com/testcontainers/testcontainers-java/issues/343
 | 
			
		||||
    try {
 | 
			
		||||
@@ -43,22 +38,22 @@ public class ElasticContainer<SELF extends ElasticContainer<SELF>> extends Gener
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static ElasticContainer<?> createAndStart() {
 | 
			
		||||
    return createAndStart(Version.V2);
 | 
			
		||||
    return createAndStart(ElasticVersion.V2_4);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static String getImageName(Version version) {
 | 
			
		||||
  private static String getImageName(ElasticVersion version) {
 | 
			
		||||
    switch (version) {
 | 
			
		||||
      case V2:
 | 
			
		||||
      case V2_4:
 | 
			
		||||
        return "elasticsearch:2.4.6-alpine";
 | 
			
		||||
      case V5:
 | 
			
		||||
      case V5_6:
 | 
			
		||||
        return "elasticsearch:5.6.9-alpine";
 | 
			
		||||
      case V6:
 | 
			
		||||
      case V6_2:
 | 
			
		||||
        return "docker.elastic.co/elasticsearch/elasticsearch:6.2.4";
 | 
			
		||||
    }
 | 
			
		||||
    throw new IllegalStateException("Unsupported version: " + version.name());
 | 
			
		||||
    throw new IllegalStateException("No tests for version: " + version.name());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private ElasticContainer(Version version) {
 | 
			
		||||
  private ElasticContainer(ElasticVersion version) {
 | 
			
		||||
    super(getImageName(version));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
// Copyright (C) 2018 The Android Open Source Project
 | 
			
		||||
//
 | 
			
		||||
// 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.google.gerrit.elasticsearch;
 | 
			
		||||
 | 
			
		||||
import static com.google.common.truth.Truth.assertThat;
 | 
			
		||||
 | 
			
		||||
import org.junit.Rule;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.rules.ExpectedException;
 | 
			
		||||
 | 
			
		||||
public class ElasticVersionTest {
 | 
			
		||||
  @Rule public ExpectedException exception = ExpectedException.none();
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void supportedVersion() throws Exception {
 | 
			
		||||
    assertThat(ElasticVersion.forVersion("2.4.0")).isEqualTo(ElasticVersion.V2_4);
 | 
			
		||||
    assertThat(ElasticVersion.forVersion("2.4.6")).isEqualTo(ElasticVersion.V2_4);
 | 
			
		||||
 | 
			
		||||
    assertThat(ElasticVersion.forVersion("5.6.0")).isEqualTo(ElasticVersion.V5_6);
 | 
			
		||||
    assertThat(ElasticVersion.forVersion("5.6.9")).isEqualTo(ElasticVersion.V5_6);
 | 
			
		||||
 | 
			
		||||
    assertThat(ElasticVersion.forVersion("6.2.0")).isEqualTo(ElasticVersion.V6_2);
 | 
			
		||||
    assertThat(ElasticVersion.forVersion("6.2.4")).isEqualTo(ElasticVersion.V6_2);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void unsupportedVersion() throws Exception {
 | 
			
		||||
    exception.expect(ElasticVersion.InvalidVersion.class);
 | 
			
		||||
    exception.expectMessage(
 | 
			
		||||
        "Invalid version: [4.0.0]. Supported versions: " + ElasticVersion.supportedVersions());
 | 
			
		||||
    ElasticVersion.forVersion("4.0.0");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -34,6 +34,10 @@ public final class FieldDef<I, T> {
 | 
			
		||||
    return new FieldDef.Builder<>(FieldType.EXACT, name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static FieldDef.Builder<String> keyword(String name) {
 | 
			
		||||
    return new FieldDef.Builder<>(FieldType.KEYWORD, name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static FieldDef.Builder<String> fullText(String name) {
 | 
			
		||||
    return new FieldDef.Builder<>(FieldType.FULL_TEXT, name);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,9 @@ public class FieldType<T> {
 | 
			
		||||
  /** A string field searched using exact-match semantics. */
 | 
			
		||||
  public static final FieldType<String> EXACT = new FieldType<>("EXACT");
 | 
			
		||||
 | 
			
		||||
  /** A Keyword field searched using non-analyzed-match semantics. */
 | 
			
		||||
  public static final FieldType<String> KEYWORD = new FieldType<>("KEYWORD");
 | 
			
		||||
 | 
			
		||||
  /** A string field searched using prefix. */
 | 
			
		||||
  public static final FieldType<String> PREFIX = new FieldType<>("PREFIX");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -311,7 +311,7 @@ public abstract class AbstractLuceneIndex<K, V> implements Index<K, V> {
 | 
			
		||||
      for (Object value : values.getValues()) {
 | 
			
		||||
        doc.add(new LongField(name, ((Timestamp) value).getTime(), store));
 | 
			
		||||
      }
 | 
			
		||||
    } else if (type == FieldType.EXACT || type == FieldType.PREFIX) {
 | 
			
		||||
    } else if (type == FieldType.KEYWORD || type == FieldType.EXACT || type == FieldType.PREFIX) {
 | 
			
		||||
      for (Object value : values.getValues()) {
 | 
			
		||||
        doc.add(new StringField(name, (String) value, store));
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -141,20 +141,21 @@ public class QueryBuilder<V> {
 | 
			
		||||
        "field not in schema v%s: %s",
 | 
			
		||||
        schema.getVersion(),
 | 
			
		||||
        p.getField().getName());
 | 
			
		||||
    if (p.getType() == FieldType.INTEGER) {
 | 
			
		||||
    FieldType<?> type = p.getType();
 | 
			
		||||
    if (type == FieldType.INTEGER) {
 | 
			
		||||
      return intQuery(p);
 | 
			
		||||
    } else if (p.getType() == FieldType.INTEGER_RANGE) {
 | 
			
		||||
    } else if (type == FieldType.INTEGER_RANGE) {
 | 
			
		||||
      return intRangeQuery(p);
 | 
			
		||||
    } else if (p.getType() == FieldType.TIMESTAMP) {
 | 
			
		||||
    } else if (type == FieldType.TIMESTAMP) {
 | 
			
		||||
      return timestampQuery(p);
 | 
			
		||||
    } else if (p.getType() == FieldType.EXACT) {
 | 
			
		||||
    } else if (type == FieldType.EXACT || type == FieldType.KEYWORD) {
 | 
			
		||||
      return exactQuery(p);
 | 
			
		||||
    } else if (p.getType() == FieldType.PREFIX) {
 | 
			
		||||
    } else if (type == FieldType.PREFIX) {
 | 
			
		||||
      return prefixQuery(p);
 | 
			
		||||
    } else if (p.getType() == FieldType.FULL_TEXT) {
 | 
			
		||||
    } else if (type == FieldType.FULL_TEXT) {
 | 
			
		||||
      return fullTextQuery(p);
 | 
			
		||||
    } else {
 | 
			
		||||
      throw FieldType.badFieldType(p.getType());
 | 
			
		||||
      throw FieldType.badFieldType(type);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
 | 
			
		||||
import static com.google.gerrit.index.FieldDef.exact;
 | 
			
		||||
import static com.google.gerrit.index.FieldDef.fullText;
 | 
			
		||||
import static com.google.gerrit.index.FieldDef.integer;
 | 
			
		||||
import static com.google.gerrit.index.FieldDef.keyword;
 | 
			
		||||
import static com.google.gerrit.index.FieldDef.prefix;
 | 
			
		||||
import static com.google.gerrit.index.FieldDef.timestamp;
 | 
			
		||||
 | 
			
		||||
@@ -36,11 +37,11 @@ public class GroupField {
 | 
			
		||||
 | 
			
		||||
  /** Group UUID. */
 | 
			
		||||
  public static final FieldDef<InternalGroup, String> UUID =
 | 
			
		||||
      exact("uuid").stored().build(g -> g.getGroupUUID().get());
 | 
			
		||||
      keyword("uuid").stored().build(g -> g.getGroupUUID().get());
 | 
			
		||||
 | 
			
		||||
  /** Group owner UUID. */
 | 
			
		||||
  public static final FieldDef<InternalGroup, String> OWNER_UUID =
 | 
			
		||||
      exact("owner_uuid").build(g -> g.getOwnerGroupUUID().get());
 | 
			
		||||
      keyword("owner_uuid").build(g -> g.getOwnerGroupUUID().get());
 | 
			
		||||
 | 
			
		||||
  /** Timestamp indicating when this group was created. */
 | 
			
		||||
  public static final FieldDef<InternalGroup, Timestamp> CREATED_ON =
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user