nastra commented on code in PR #5780:
URL: https://github.com/apache/iceberg/pull/5780#discussion_r974960351


##########
api/src/main/java/org/apache/iceberg/metrics/ScanReport.java:
##########
@@ -419,86 +154,60 @@ public static class ScanMetrics {
     public static final String TOTAL_FILE_SIZE_IN_BYTES = 
"total-file-size-in-bytes";
     public static final String TOTAL_DELETE_FILE_SIZE_IN_BYTES = 
"total-delete-file-size-in-bytes";
     public static final String SKIPPED_DATA_MANIFESTS = 
"skipped-data-manifests";
-    private final Timer totalPlanningDuration;
-    private final Counter resultDataFiles;
-    private final Counter resultDeleteFiles;
-    private final Counter totalDataManifests;
-    private final Counter totalDeleteManifests;
-    private final Counter scannedDataManifests;
-    private final Counter skippedDataManifests;
-    private final Counter totalFileSizeInBytes;
-    private final Counter totalDeleteFileSizeInBytes;
-
-    public ScanMetrics(MetricsContext metricsContext) {
-      Preconditions.checkArgument(null != metricsContext, "Invalid metrics 
context: null");
-      this.totalPlanningDuration =
-          metricsContext.timer(TOTAL_PLANNING_DURATION, TimeUnit.NANOSECONDS);
-      this.resultDataFiles = metricsContext.counter(RESULT_DATA_FILES, 
MetricsContext.Unit.COUNT);
-      this.resultDeleteFiles =
-          metricsContext.counter(RESULT_DELETE_FILES, 
MetricsContext.Unit.COUNT);
-      this.scannedDataManifests =
-          metricsContext.counter(SCANNED_DATA_MANIFESTS, 
MetricsContext.Unit.COUNT);
-      this.totalDataManifests =
-          metricsContext.counter(TOTAL_DATA_MANIFESTS, 
MetricsContext.Unit.COUNT);
-      this.totalDeleteManifests =
-          metricsContext.counter(TOTAL_DELETE_MANIFESTS, 
MetricsContext.Unit.COUNT);
-      this.totalFileSizeInBytes =
-          metricsContext.counter(TOTAL_FILE_SIZE_IN_BYTES, 
MetricsContext.Unit.BYTES);
-      this.totalDeleteFileSizeInBytes =
-          metricsContext.counter(TOTAL_DELETE_FILE_SIZE_IN_BYTES, 
MetricsContext.Unit.BYTES);
-      this.skippedDataManifests =
-          metricsContext.counter(SKIPPED_DATA_MANIFESTS, 
MetricsContext.Unit.COUNT);
+
+    public static ScanMetrics noop() {
+      return ScanMetrics.of(MetricsContext.nullMetrics());
     }
 
+    public abstract MetricsContext metricsContext();
+
+    @Value.Derived
     public Timer totalPlanningDuration() {
-      return totalPlanningDuration;
+      return metricsContext().timer(TOTAL_PLANNING_DURATION, 
TimeUnit.NANOSECONDS);

Review Comment:
   I see the `MetricsContext` parameter here less as a "this class needs to 
keep track of this" but rather "this is what's required to create an instance 
of this class". Your comment is perfectly valid here and I initially had the 
exact same thought. 
   Therefore it make sense to have a `ScanMetrics.from(MetricsContext)`. In 
fact we have a `ScanMetrics.of(MetricsContext)` that does exactly that. 
   
   We could go ahead and change `ScanMetrics.of(...)` to:
   ```
   public static ScanMetrics of(MetricsContext metricsContext) {
         return ImmutableScanMetrics.builder()
             .metricsContext(metricsContext)
             .totalPlanningDuration(
                 metricsContext.timer(TOTAL_PLANNING_DURATION, 
TimeUnit.NANOSECONDS))
             .resultDataFiles(metricsContext.counter(RESULT_DATA_FILES, 
MetricsContext.Unit.COUNT))
             .resultDeleteFiles(metricsContext.counter(RESULT_DELETE_FILES, 
MetricsContext.Unit.COUNT))
             .scannedDataManifests(
                 metricsContext.counter(SCANNED_DATA_MANIFESTS, 
MetricsContext.Unit.COUNT))
             .totalDataManifests(
                 metricsContext.counter(TOTAL_DATA_MANIFESTS, 
MetricsContext.Unit.COUNT))
             .totalDeleteManifests(
                 metricsContext.counter(TOTAL_DELETE_MANIFESTS, 
MetricsContext.Unit.COUNT))
             .totalFileSizeInBytes(
                 metricsContext.counter(TOTAL_FILE_SIZE_IN_BYTES, 
MetricsContext.Unit.BYTES))
             .totalDeleteFileSizeInBytes(
                 metricsContext.counter(TOTAL_DELETE_FILE_SIZE_IN_BYTES, 
MetricsContext.Unit.BYTES))
             .skippedDataManifests(
                 metricsContext.counter(SKIPPED_DATA_MANIFESTS, 
MetricsContext.Unit.COUNT))
             .build();
       }
   ```
   It would produce the exact same results. The only reason I went with 
`@Value.Derived` is because it does not allow manual creation of metric 
instances.
   `ScanMetrics.of(...)` is just a utility method and it doesn't prevent anyone 
from using the Builder directly. Using `@Value.Derived` in this context means 
essentially that all those metric instances are derived from `MetricsContext` 
but **cannot be manually set**, thus providing a builder where only 
`ImmutableScanMetrics.builder()        .metricsContext(metricsContext).build()` 
can be set.
   The lazy initialization of metrics that `@Value.Derived` provides is just a 
nice thing to have that we get here, but my main motivation was to prevent the 
different counters/timers to be manually set. This gives us the exact same 
semantics we had in the previous `ScanMetrics` API, since all the metrics were 
initialized in the constructor.
   
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to