update method
Insert new data points or modify old ones with matching id.
Implementation
@override
Future<void> update(
List<MetricPoint> points, DateTime commitTime, String taskName) async {
// 1st, create a map based on git repo, git revision, and point id. Git repo
// and git revision are the top level components of the Skia perf GCS object
// name.
final Map<String, Map<String?, Map<String, SkiaPerfPoint>>> pointMap =
<String, Map<String, Map<String, SkiaPerfPoint>>>{};
for (final SkiaPerfPoint p
in points.map((MetricPoint x) => SkiaPerfPoint.fromPoint(x))) {
pointMap[p.githubRepo] ??= <String, Map<String, SkiaPerfPoint>>{};
pointMap[p.githubRepo]![p.gitHash] ??= <String, SkiaPerfPoint>{};
pointMap[p.githubRepo]![p.gitHash]![p.id] = p;
}
// All created locks must be released before returning
final List<Future<void>> lockFutures = <Future<void>>[];
// 2nd, read existing points from the gcs object and update with new ones.
for (final String repo in pointMap.keys) {
for (final String? revision in pointMap[repo]!.keys) {
final String objectName = await SkiaPerfGcsAdaptor.computeObjectName(
repo, revision, commitTime, taskName);
final Map<String, SkiaPerfPoint>? newPoints = pointMap[repo]![revision];
// Too many bots writing the metrics of a git revision into a single json
// file will cause high contention on the lock. We use multiple
// json files according to task names. Skia perf read all json files in
// the directory so one can use arbitrary names for those sharded json
// file names.
lockFutures.add(
_lock!.protectedRun('$objectName.lock', () async {
final List<SkiaPerfPoint> oldPoints =
await _gcs.readPoints(objectName);
for (final SkiaPerfPoint p in oldPoints) {
if (newPoints![p.id] == null) {
newPoints[p.id] = p;
}
}
await _gcs.writePoints(objectName, newPoints!.values.toList());
}),
);
}
}
await Future.wait(lockFutures);
}