private void queryContainerUsageForClusterInternal(boolean forMonthly, String clusterName,
      AggregatedContainerStorageStatsFunction func) throws SQLException {
    try (Connection connection = dataSource.getConnection()) {
      String sqlStatement = forMonthly ? queryMonthlyUsageSqlForCluster : queryUsageSqlForCluster;
      try (PreparedStatement queryStatement = connection.prepareStatement(sqlStatement)) {
        long startTimeMs = System.currentTimeMillis();
        queryStatement.setString(1, clusterName);
        try (ResultSet resultSet = queryStatement.executeQuery()) {
          while (resultSet.next()) {
            int accountId = resultSet.getInt(ACCOUNT_ID_COLUMN);
            int containerId = resultSet.getInt(CONTAINER_ID_COLUMN);
            long storageUsage = resultSet.getLong(STORAGE_USAGE_COLUMN);
            final long physicalStorageUsage = resultSet.getLong(PHYSICAL_STORAGE_USAGE_COLUMN);
            final long numberOfBlobs = resultSet.getLong(NUMBER_OF_BLOBS_COLUMN);
            func.apply((short) accountId,
                new ContainerStorageStats((short) containerId, storageUsage, physicalStorageUsage, numberOfBlobs));
          }
        }
        metrics.readTimeMs.update(System.currentTimeMillis() - startTimeMs);
        metrics.readSuccessCount.inc();
      }
    } catch (SQLException e) {
      metrics.readFailureCount.inc();
      logger.error(String.format("Failed to execute query on %s, with parameter %s", AGGREGATED_ACCOUNT_REPORTS_TABLE,
          clusterName), e);
      throw e;
    }
  }
Query container storage for the given {@code clusterName}. The result will be applied to the {@link AggregatedContainerStorageStatsFunction}.
@param forMonthly True to return the monthly snapshot of the container storage usage.
@param clusterName The clusterName.
@param func The {@link AggregatedContainerStorageStatsFunction} to call to process each container storage usage.
@throws SQLException
ambry-mysql/src/main/java/com/github/ambry/accountstats/AggregatedAccountReportsDao.java