Files
gerrit/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
David Pursehouse 390c042ab4 AbstractElasticIndex: Move generation of index name to ElasticConfiguration
ElasticConfiguration already reads all of the other configurations, so
move reading of the prefix there too.

Move generation of the indexName from AbstractElasticIndex to a helper
method in ElasticConfiguration.

AbstractElasticIndex no longer needs the @GerritServerConfig annotated
Config, and now just gets ElasticConfiguration injected.

Modify ElasticConfiguration to keep a reference to the @GerritServerConfig
annotated Config, and provide an accessor method.

ElasticVersionManager also no longer needs to get the @GerritServerConfig
annotated. It just gets the ElasticConfiguration which it uses to get
the prefix, and passes the underlying Config up to the superclass which
uses it to get the onlineReindex flag.

Change-Id: Ie4696b4d5a4e0bc58d3b2175f46002d0cc65940c
2018-05-30 19:49:28 +09:00

206 lines
7.1 KiB
Java

// Copyright (C) 2017 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.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.gerrit.elasticsearch.ElasticMapping.MappingProperties;
import com.google.gerrit.elasticsearch.builders.QueryBuilder;
import com.google.gerrit.elasticsearch.builders.SearchSourceBuilder;
import com.google.gerrit.elasticsearch.bulk.BulkRequest;
import com.google.gerrit.elasticsearch.bulk.IndexRequest;
import com.google.gerrit.elasticsearch.bulk.UpdateRequest;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.index.IndexUtils;
import com.google.gerrit.server.index.QueryOptions;
import com.google.gerrit.server.index.Schema;
import com.google.gerrit.server.index.group.GroupField;
import com.google.gerrit.server.index.group.GroupIndex;
import com.google.gerrit.server.query.DataSource;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.elasticsearch.client.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ElasticGroupIndex extends AbstractElasticIndex<AccountGroup.UUID, AccountGroup>
implements GroupIndex {
public static class GroupMapping {
MappingProperties groups;
public GroupMapping(Schema<AccountGroup> schema) {
this.groups = ElasticMapping.createMapping(schema);
}
}
public static final String GROUPS = "groups";
private static final Logger log = LoggerFactory.getLogger(ElasticGroupIndex.class);
private final GroupMapping mapping;
private final Provider<GroupCache> groupCache;
private final Schema<AccountGroup> schema;
@AssistedInject
ElasticGroupIndex(
ElasticConfiguration cfg,
SitePaths sitePaths,
Provider<GroupCache> groupCache,
ElasticRestClientBuilder clientBuilder,
@Assisted Schema<AccountGroup> schema) {
super(cfg, sitePaths, schema, clientBuilder, GROUPS);
this.groupCache = groupCache;
this.mapping = new GroupMapping(schema);
this.schema = schema;
}
@Override
public void replace(AccountGroup group) throws IOException {
BulkRequest bulk =
new IndexRequest(getId(group), indexName, GROUPS).add(new UpdateRequest<>(schema, group));
String uri = getURI(GROUPS, BULK);
Response response = postRequest(bulk, uri, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
String.format(
"Failed to replace group %s in index %s: %s",
group.getGroupUUID().get(), indexName, statusCode));
}
}
@Override
public DataSource<AccountGroup> getSource(Predicate<AccountGroup> p, QueryOptions opts)
throws QueryParseException {
return new QuerySource(p, opts);
}
@Override
protected String addActions(AccountGroup.UUID c) {
return delete(GROUPS, c);
}
@Override
protected String getMappings() {
ImmutableMap<String, GroupMapping> mappings = ImmutableMap.of("mappings", mapping);
return gson.toJson(mappings);
}
@Override
protected String getId(AccountGroup group) {
return group.getGroupUUID().get();
}
private class QuerySource implements DataSource<AccountGroup> {
private final String search;
private final Set<String> fields;
QuerySource(Predicate<AccountGroup> p, QueryOptions opts) throws QueryParseException {
QueryBuilder qb = queryBuilder.toQueryBuilder(p);
fields = IndexUtils.groupFields(opts);
SearchSourceBuilder searchSource =
new SearchSourceBuilder()
.query(qb)
.from(opts.start())
.size(opts.limit())
.fields(Lists.newArrayList(fields));
JsonArray sortArray = getSortArray(GroupField.UUID.getName());
search = getSearch(searchSource, sortArray);
}
@Override
public int getCardinality() {
return 10;
}
@Override
public ResultSet<AccountGroup> read() throws OrmException {
try {
List<AccountGroup> results = Collections.emptyList();
String uri = getURI(GROUPS, SEARCH);
Response response = postRequest(search, uri, Collections.emptyMap());
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
String content = getContent(response);
JsonObject obj =
new JsonParser().parse(content).getAsJsonObject().getAsJsonObject("hits");
if (obj.get("hits") != null) {
JsonArray json = obj.getAsJsonArray("hits");
results = Lists.newArrayListWithCapacity(json.size());
for (int i = 0; i < json.size(); i++) {
results.add(toAccountGroup(json.get(i)));
}
}
} else {
log.error(statusLine.getReasonPhrase());
}
final List<AccountGroup> r = Collections.unmodifiableList(results);
return new ResultSet<AccountGroup>() {
@Override
public Iterator<AccountGroup> iterator() {
return r.iterator();
}
@Override
public List<AccountGroup> toList() {
return r;
}
@Override
public void close() {
// Do nothing.
}
};
} catch (IOException e) {
throw new OrmException(e);
}
}
private AccountGroup toAccountGroup(JsonElement json) {
JsonElement source = json.getAsJsonObject().get("_source");
if (source == null) {
source = json.getAsJsonObject().get("fields");
}
AccountGroup.UUID uuid =
new AccountGroup.UUID(
source.getAsJsonObject().get(GroupField.UUID.getName()).getAsString());
// Use the GroupCache rather than depending on any stored fields in the
// document (of which there shouldn't be any).
return groupCache.get().get(uuid);
}
}
}