Instrument ChangeJson to estimate parallelization performance upside
Change-Id: I9b559b00a1bbf0e7b588ddfff5062268df28ab9a
This commit is contained in:
@@ -55,6 +55,12 @@ objects needing finalization.
|
|||||||
* `http/server/rest_api/server_latency`: REST API call latency by view.
|
* `http/server/rest_api/server_latency`: REST API call latency by view.
|
||||||
* `http/server/rest_api/response_bytes`: Size of REST API response on network
|
* `http/server/rest_api/response_bytes`: Size of REST API response on network
|
||||||
(may be gzip compressed) by view.
|
(may be gzip compressed) by view.
|
||||||
|
* `http/server/rest_api/change_json/to_change_info_latency`: Latency for
|
||||||
|
toChangeInfo invocations in ChangeJson.
|
||||||
|
* `http/server/rest_api/change_json/to_change_infos_latency`: Latency for
|
||||||
|
toChangeInfos invocations in ChangeJson.
|
||||||
|
* `http/server/rest_api/change_json/format_query_results_latency`: Latency for
|
||||||
|
formatQueryResults invocations in ChangeJson.
|
||||||
|
|
||||||
=== Query
|
=== Query
|
||||||
|
|
||||||
|
@@ -87,6 +87,10 @@ import com.google.gerrit.extensions.registration.DynamicMap;
|
|||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
import com.google.gerrit.extensions.restapi.Url;
|
import com.google.gerrit.extensions.restapi.Url;
|
||||||
import com.google.gerrit.index.query.QueryResult;
|
import com.google.gerrit.index.query.QueryResult;
|
||||||
|
import com.google.gerrit.metrics.Description;
|
||||||
|
import com.google.gerrit.metrics.Description.Units;
|
||||||
|
import com.google.gerrit.metrics.MetricMaker;
|
||||||
|
import com.google.gerrit.metrics.Timer0;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gerrit.reviewdb.client.ChangeMessage;
|
import com.google.gerrit.reviewdb.client.ChangeMessage;
|
||||||
@@ -202,6 +206,35 @@ public class ChangeJson {
|
|||||||
ChangeJson create(Iterable<ListChangesOption> options);
|
ChangeJson create(Iterable<ListChangesOption> options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
private static class Metrics {
|
||||||
|
private final Timer0 toChangeInfoLatency;
|
||||||
|
private final Timer0 toChangeInfosLatency;
|
||||||
|
private final Timer0 formatQueryResultsLatency;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Metrics(MetricMaker metricMaker) {
|
||||||
|
toChangeInfoLatency =
|
||||||
|
metricMaker.newTimer(
|
||||||
|
"http/server/rest_api/change_json/to_change_info_latency",
|
||||||
|
new Description("Latency for toChangeInfo invocations in ChangeJson")
|
||||||
|
.setCumulative()
|
||||||
|
.setUnit(Units.MILLISECONDS));
|
||||||
|
toChangeInfosLatency =
|
||||||
|
metricMaker.newTimer(
|
||||||
|
"http/server/rest_api/change_json/to_change_infos_latency",
|
||||||
|
new Description("Latency for toChangeInfos invocations in ChangeJson")
|
||||||
|
.setCumulative()
|
||||||
|
.setUnit(Units.MILLISECONDS));
|
||||||
|
formatQueryResultsLatency =
|
||||||
|
metricMaker.newTimer(
|
||||||
|
"http/server/rest_api/change_json/format_query_results_latency",
|
||||||
|
new Description("Latency for formatQueryResults invocations in ChangeJson")
|
||||||
|
.setCumulative()
|
||||||
|
.setUnit(Units.MILLISECONDS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final Provider<ReviewDb> db;
|
private final Provider<ReviewDb> db;
|
||||||
private final Provider<CurrentUser> userProvider;
|
private final Provider<CurrentUser> userProvider;
|
||||||
private final AnonymousUser anonymous;
|
private final AnonymousUser anonymous;
|
||||||
@@ -228,6 +261,7 @@ public class ChangeJson {
|
|||||||
private final ApprovalsUtil approvalsUtil;
|
private final ApprovalsUtil approvalsUtil;
|
||||||
private final RemoveReviewerControl removeReviewerControl;
|
private final RemoveReviewerControl removeReviewerControl;
|
||||||
private final TrackingFooters trackingFooters;
|
private final TrackingFooters trackingFooters;
|
||||||
|
private final Metrics metrics;
|
||||||
private boolean lazyLoad = true;
|
private boolean lazyLoad = true;
|
||||||
private AccountLoader accountLoader;
|
private AccountLoader accountLoader;
|
||||||
private FixInput fix;
|
private FixInput fix;
|
||||||
@@ -260,6 +294,7 @@ public class ChangeJson {
|
|||||||
ApprovalsUtil approvalsUtil,
|
ApprovalsUtil approvalsUtil,
|
||||||
RemoveReviewerControl removeReviewerControl,
|
RemoveReviewerControl removeReviewerControl,
|
||||||
TrackingFooters trackingFooters,
|
TrackingFooters trackingFooters,
|
||||||
|
Metrics metrics,
|
||||||
@Assisted Iterable<ListChangesOption> options) {
|
@Assisted Iterable<ListChangesOption> options) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.userProvider = user;
|
this.userProvider = user;
|
||||||
@@ -285,8 +320,9 @@ public class ChangeJson {
|
|||||||
this.indexes = indexes;
|
this.indexes = indexes;
|
||||||
this.approvalsUtil = approvalsUtil;
|
this.approvalsUtil = approvalsUtil;
|
||||||
this.removeReviewerControl = removeReviewerControl;
|
this.removeReviewerControl = removeReviewerControl;
|
||||||
this.options = Sets.immutableEnumSet(options);
|
|
||||||
this.trackingFooters = trackingFooters;
|
this.trackingFooters = trackingFooters;
|
||||||
|
this.metrics = metrics;
|
||||||
|
this.options = Sets.immutableEnumSet(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChangeJson lazyLoad(boolean load) {
|
public ChangeJson lazyLoad(boolean load) {
|
||||||
@@ -360,20 +396,22 @@ public class ChangeJson {
|
|||||||
|
|
||||||
public List<List<ChangeInfo>> formatQueryResults(List<QueryResult<ChangeData>> in)
|
public List<List<ChangeInfo>> formatQueryResults(List<QueryResult<ChangeData>> in)
|
||||||
throws OrmException {
|
throws OrmException {
|
||||||
accountLoader = accountLoaderFactory.create(has(DETAILED_ACCOUNTS));
|
try (Timer0.Context ignored = metrics.formatQueryResultsLatency.start()) {
|
||||||
ensureLoaded(FluentIterable.from(in).transformAndConcat(QueryResult::entities));
|
accountLoader = accountLoaderFactory.create(has(DETAILED_ACCOUNTS));
|
||||||
|
ensureLoaded(FluentIterable.from(in).transformAndConcat(QueryResult::entities));
|
||||||
|
|
||||||
List<List<ChangeInfo>> res = Lists.newArrayListWithCapacity(in.size());
|
List<List<ChangeInfo>> res = Lists.newArrayListWithCapacity(in.size());
|
||||||
Map<Change.Id, ChangeInfo> out = new HashMap<>();
|
Map<Change.Id, ChangeInfo> out = new HashMap<>();
|
||||||
for (QueryResult<ChangeData> r : in) {
|
for (QueryResult<ChangeData> r : in) {
|
||||||
List<ChangeInfo> infos = toChangeInfo(out, r.entities());
|
List<ChangeInfo> infos = toChangeInfos(out, r.entities());
|
||||||
if (!infos.isEmpty() && r.more()) {
|
if (!infos.isEmpty() && r.more()) {
|
||||||
infos.get(infos.size() - 1)._moreChanges = true;
|
infos.get(infos.size() - 1)._moreChanges = true;
|
||||||
|
}
|
||||||
|
res.add(infos);
|
||||||
}
|
}
|
||||||
res.add(infos);
|
accountLoader.fill();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
accountLoader.fill();
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ChangeInfo> formatChangeDatas(Collection<ChangeData> in) throws OrmException {
|
public List<ChangeInfo> formatChangeDatas(Collection<ChangeData> in) throws OrmException {
|
||||||
@@ -410,37 +448,39 @@ public class ChangeJson {
|
|||||||
return options.contains(option);
|
return options.contains(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ChangeInfo> toChangeInfo(Map<Change.Id, ChangeInfo> out, List<ChangeData> changes) {
|
private List<ChangeInfo> toChangeInfos(Map<Change.Id, ChangeInfo> out, List<ChangeData> changes) {
|
||||||
List<ChangeInfo> info = Lists.newArrayListWithCapacity(changes.size());
|
try (Timer0.Context ignored = metrics.toChangeInfosLatency.start()) {
|
||||||
for (ChangeData cd : changes) {
|
List<ChangeInfo> info = Lists.newArrayListWithCapacity(changes.size());
|
||||||
ChangeInfo i = out.get(cd.getId());
|
for (ChangeData cd : changes) {
|
||||||
if (i == null) {
|
ChangeInfo i = out.get(cd.getId());
|
||||||
try {
|
if (i == null) {
|
||||||
i = toChangeInfo(cd, Optional.empty());
|
try {
|
||||||
} catch (PatchListNotAvailableException
|
i = toChangeInfo(cd, Optional.empty());
|
||||||
| GpgException
|
} catch (PatchListNotAvailableException
|
||||||
| OrmException
|
| GpgException
|
||||||
| IOException
|
| OrmException
|
||||||
| PermissionBackendException
|
| IOException
|
||||||
| RuntimeException e) {
|
| PermissionBackendException
|
||||||
if (has(CHECK)) {
|
| RuntimeException e) {
|
||||||
i = checkOnly(cd);
|
if (has(CHECK)) {
|
||||||
} else if (e instanceof NoSuchChangeException) {
|
i = checkOnly(cd);
|
||||||
log.info(
|
} else if (e instanceof NoSuchChangeException) {
|
||||||
"NoSuchChangeException: Omitting corrupt change "
|
log.info(
|
||||||
+ cd.getId()
|
"NoSuchChangeException: Omitting corrupt change "
|
||||||
+ " from results. Seems to be stale in the index.");
|
+ cd.getId()
|
||||||
continue;
|
+ " from results. Seems to be stale in the index.");
|
||||||
} else {
|
continue;
|
||||||
log.warn("Omitting corrupt change " + cd.getId() + " from results", e);
|
} else {
|
||||||
continue;
|
log.warn("Omitting corrupt change " + cd.getId() + " from results", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
out.put(cd.getId(), i);
|
||||||
}
|
}
|
||||||
out.put(cd.getId(), i);
|
info.add(i);
|
||||||
}
|
}
|
||||||
info.add(i);
|
return info;
|
||||||
}
|
}
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChangeInfo checkOnly(ChangeData cd) {
|
private ChangeInfo checkOnly(ChangeData cd) {
|
||||||
@@ -489,6 +529,14 @@ public class ChangeJson {
|
|||||||
private ChangeInfo toChangeInfo(ChangeData cd, Optional<PatchSet.Id> limitToPsId)
|
private ChangeInfo toChangeInfo(ChangeData cd, Optional<PatchSet.Id> limitToPsId)
|
||||||
throws PatchListNotAvailableException, GpgException, OrmException, PermissionBackendException,
|
throws PatchListNotAvailableException, GpgException, OrmException, PermissionBackendException,
|
||||||
IOException {
|
IOException {
|
||||||
|
try (Timer0.Context ignored = metrics.toChangeInfoLatency.start()) {
|
||||||
|
return toChangeInfoImpl(cd, limitToPsId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChangeInfo toChangeInfoImpl(ChangeData cd, Optional<PatchSet.Id> limitToPsId)
|
||||||
|
throws PatchListNotAvailableException, GpgException, OrmException, PermissionBackendException,
|
||||||
|
IOException {
|
||||||
ChangeInfo out = new ChangeInfo();
|
ChangeInfo out = new ChangeInfo();
|
||||||
CurrentUser user = userProvider.get();
|
CurrentUser user = userProvider.get();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user