Files
gerrit/java/com/google/gerrit/index/Schema.java
Orgad Shaneh 061f3b238a Schema: Show only a single log for inexistent commits
Producing 16 logs for each commit is pointless.

Finding an OrmException means we're going to hit exceptions again
and again for each field, so bubble them up and return an empty list
when we find one.

Example (unmodified from cherry-pick source where OrmException has been
renamed to StorageException):
[2020-06-07T13:28:28.346+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field added of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
com.google.gerrit.exceptions.StorageException: Loading commit AnyObjectId[cee21a4ec8b5ae2469f7f314c2548dedc1023293] for ps 2 of change 777 failed.
	at com.google.gerrit.server.query.change.ChangeData.loadCommitData(ChangeData.java:596)
	at com.google.gerrit.server.query.change.ChangeData.getDiffSummary(ChangeData.java:398)
	at com.google.gerrit.server.query.change.ChangeData.computeChangedLines(ChangeData.java:414)
[2020-06-07T13:28:28.352+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field author of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.355+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field committer of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.357+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field message of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.358+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field deleted of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.360+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field delta of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.361+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field directory of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.364+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field exactauthor of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.365+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field exactcommitter of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.367+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field extension of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.375+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field filepart of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.377+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field footer of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.379+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field onlyextensions of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.380+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field file of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.388+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field tr of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}
[2020-06-07T13:28:28.390+0300] [Index-Batch-1] ERROR com.google.gerrit.index.Schema : error getting field merge of ChangeData{Change{777 (Ia3439cd1765c9a7a08a07a1485fbc95aabd8cf56), dest=Project,refs/heads/master, status=M}}

Change-Id: If23916d20134c869999d2588316936f29b0701db
(cherry picked from commit 7c7b8d86a1)
2020-06-12 12:29:42 -06:00

222 lines
6.5 KiB
Java

// Copyright (C) 2013 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.index;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import com.google.gwtorm.server.OrmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/** Specific version of a secondary index schema. */
public class Schema<T> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
public static class Builder<T> {
private final List<FieldDef<T, ?>> fields = new ArrayList<>();
public Builder<T> add(Schema<T> schema) {
this.fields.addAll(schema.getFields().values());
return this;
}
@SafeVarargs
public final Builder<T> add(FieldDef<T, ?>... fields) {
this.fields.addAll(Arrays.asList(fields));
return this;
}
@SafeVarargs
public final Builder<T> remove(FieldDef<T, ?>... fields) {
this.fields.removeAll(Arrays.asList(fields));
return this;
}
public Schema<T> build() {
return new Schema<>(ImmutableList.copyOf(fields));
}
}
public static class Values<T> {
private final FieldDef<T, ?> field;
private final Iterable<?> values;
private Values(FieldDef<T, ?> field, Iterable<?> values) {
this.field = field;
this.values = values;
}
public FieldDef<T, ?> getField() {
return field;
}
public Iterable<?> getValues() {
return values;
}
}
private static <T> FieldDef<T, ?> checkSame(FieldDef<T, ?> f1, FieldDef<T, ?> f2) {
checkState(f1 == f2, "Mismatched %s fields: %s != %s", f1.getName(), f1, f2);
return f1;
}
private final ImmutableMap<String, FieldDef<T, ?>> fields;
private final ImmutableMap<String, FieldDef<T, ?>> storedFields;
private int version;
public Schema(Iterable<FieldDef<T, ?>> fields) {
this(0, fields);
}
public Schema(int version, Iterable<FieldDef<T, ?>> fields) {
this.version = version;
ImmutableMap.Builder<String, FieldDef<T, ?>> b = ImmutableMap.builder();
ImmutableMap.Builder<String, FieldDef<T, ?>> sb = ImmutableMap.builder();
for (FieldDef<T, ?> f : fields) {
b.put(f.getName(), f);
if (f.isStored()) {
sb.put(f.getName(), f);
}
}
this.fields = b.build();
this.storedFields = sb.build();
}
public final int getVersion() {
return version;
}
/**
* Get all fields in this schema.
*
* <p>This is primarily useful for iteration. Most callers should prefer one of the helper methods
* {@link #getField(FieldDef, FieldDef...)} or {@link #hasField(FieldDef)} to looking up fields by
* name
*
* @return all fields in this schema indexed by name.
*/
public final ImmutableMap<String, FieldDef<T, ?>> getFields() {
return fields;
}
/** @return all fields in this schema where {@link FieldDef#isStored()} is true. */
public final ImmutableMap<String, FieldDef<T, ?>> getStoredFields() {
return storedFields;
}
/**
* Look up fields in this schema.
*
* @param first the preferred field to look up.
* @param rest additional fields to look up.
* @return the first field in the schema matching {@code first} or {@code rest}, in order, or
* absent if no field matches.
*/
@SafeVarargs
public final Optional<FieldDef<T, ?>> getField(FieldDef<T, ?> first, FieldDef<T, ?>... rest) {
FieldDef<T, ?> field = fields.get(first.getName());
if (field != null) {
return Optional.of(checkSame(field, first));
}
for (FieldDef<T, ?> f : rest) {
field = fields.get(f.getName());
if (field != null) {
return Optional.of(checkSame(field, f));
}
}
return Optional.empty();
}
/**
* Check whether a field is present in this schema.
*
* @param field field to look up.
* @return whether the field is present.
*/
public final boolean hasField(FieldDef<T, ?> field) {
FieldDef<T, ?> f = fields.get(field.getName());
if (f == null) {
return false;
}
checkSame(f, field);
return true;
}
private Values<T> fieldValues(T obj, FieldDef<T, ?> f) {
Object v;
try {
v = f.get(obj);
} catch (OrmException e) {
// OrmException is thrown when the object is not found. On this case,
// it is pointless to make further attempts for each field, so propagate
// the exception to return an empty list.
logger.atSevere().withCause(e).log("error getting field %s of %s", f.getName(), obj);
throw new RuntimeException(
e); // work around throwing checked exceptions from methods used in Streams
} catch (RuntimeException e) {
logger.atSevere().withCause(e).log("error getting field %s of %s", f.getName(), obj);
return null;
}
if (v == null) {
return null;
} else if (f.isRepeatable()) {
return new Values<>(f, (Iterable<?>) v);
} else {
return new Values<>(f, Collections.singleton(v));
}
}
/**
* Build all fields in the schema from an input object.
*
* <p>Null values are omitted, as are fields which cause errors, which are logged.
*
* @param obj input object.
* @return all non-null field values from the object.
*/
public final Iterable<Values<T>> buildFields(T obj) {
try {
return fields.values().stream()
.map(f -> fieldValues(obj, f))
.filter(Objects::nonNull)
.collect(toImmutableList());
} catch (RuntimeException e) {
if (e.getCause().getClass().equals(OrmException.class)) {
return ImmutableList.of();
}
throw e;
}
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).addValue(fields.keySet()).toString();
}
public void setVersion(int version) {
this.version = version;
}
}