docs: public static MetricRequest fromProtobuf(TopologyMaster.MetricRequest request) {
      String componentName = request.getComponentName();
  
      Map<String, Set<String>> componentNameInstanceId = new HashMap<>();
      if (request.getInstanceIdCount() == 0) {
        // empty list means all instances
        // 'null' means all instances
        componentNameInstanceId.put(componentName, null);
      } else {
        Set<String> instances = new HashSet<>();
        // only one component
        componentNameInstanceId.put(componentName, instances);
        // if there are instances specified
        instances.addAll(request.getInstanceIdList());
      }
  
      Set<String> metricNames = new HashSet<>();
      if (request.getMetricCount() > 0) {
        metricNames.addAll(request.getMetricList());
      } // empty list means no metrics
  
      // default: the whole time horizon
      long startTime = 0;
      long endTime = Long.MAX_VALUE;
      if (request.hasInterval()) { // endTime = now
        endTime = System.currentTimeMillis();
  
        long interval = request.getInterval(); // in seconds
        if (interval <= 0) { // means all
          startTime = 0;
        } else { // means [-interval, now]
          startTime = endTime - interval * 1000;
        }
      } else {
        startTime = request.getExplicitInterval().getStart() * 1000;
        endTime = request.getExplicitInterval().getEnd() * 1000;
      }
  
      // default: aggregate all metrics
      MetricGranularity aggregationGranularity = AGGREGATE_ALL_METRICS;
      if (request.hasMinutely() && request.getMinutely()) {
        aggregationGranularity = AGGREGATE_BY_BUCKET;
      }
  
      return new MetricRequest(componentNameInstanceId, metricNames,
          startTime, endTime, aggregationGranularity);
    }