void queryAggregatedPartitionClassReport(String clusterName, PartitionClassContainerStorageStatsFunction func)
      throws SQLException {
    try (Connection connection = dataSource.getConnection()) {
      try (PreparedStatement queryStatement = connection.prepareStatement(queryAggregatedSql)) {
        long startTimeMs = System.currentTimeMillis();
        queryStatement.setString(1, clusterName);
        try (ResultSet rs = queryStatement.executeQuery()) {
          while (rs.next()) {
            String partitionClassName = rs.getString(NAME_COLUMN);
            int accountId = rs.getInt(ACCOUNT_ID_COLUMN);
            int containerId = rs.getInt(CONTAINER_ID_COLUMN);
            long usage = rs.getLong(STORAGE_USAGE_COLUMN);
            final long physicalStorageUsage = rs.getLong(PHYSICAL_STORAGE_USAGE_COLUMN);
            final long numberOfBlobs = rs.getLong(NUMBER_OF_BLOBS_COLUMN);
            long updatedAt = rs.getTimestamp(UPDATED_AT_COLUMN).getTime();
            func.apply(partitionClassName, (short) accountId,
                new ContainerStorageStats((short) containerId, usage, physicalStorageUsage, numberOfBlobs), updatedAt);
          }
        }
        metrics.readTimeMs.update(System.currentTimeMillis() - startTimeMs);
        metrics.readSuccessCount.inc();
      }
    } catch (SQLException e) {
      metrics.readFailureCount.inc();
      logger.error("Failed to execute query {}, with parameter {}", queryAggregatedSql, clusterName, e);
      throw e;
    }
  }
Query container storage usage for given {@code clusterName}. This usage is aggregated under each partition class name.
The results will be applied to the given {@link PartitionClassContainerStorageStatsFunction}.
@param clusterName The clusterName.
@param func The callback to apply query results
@throws SQLException
ambry-mysql/src/main/java/com/github/ambry/accountstats/PartitionClassReportsDao.java