This is an automated email from the ASF dual-hosted git repository.

ycai pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 04b0d095 CASSSIDECAR-165: Add metric to report consistency check 
duration (#150)
04b0d095 is described below

commit 04b0d095c233f1b2f918446852c326caaf0125a2
Author: Yifan Cai <[email protected]>
AuthorDate: Wed Nov 20 15:21:34 2024 -0800

    CASSSIDECAR-165: Add metric to report consistency check duration (#150)
    
    Patch by Yifan Cai; Reviewed by Francisco Guerrero for CASSSIDECAR-165
---
 CHANGES.txt                                        |  1 +
 .../yaml/AccessControlConfigurationImpl.java       |  2 +-
 .../cassandra/sidecar/metrics/NamedMetric.java     | 18 +++++---
 .../cassandra/sidecar/metrics/RestoreMetrics.java  | 54 ++++++++--------------
 .../restore/RestoreJobConsistencyLevelChecker.java | 15 ++++--
 .../routes/restore/BaseRestoreJobTests.java        |  3 ++
 .../restore/RestoreJobProgressHandlerTest.java     |  3 ++
 7 files changed, 51 insertions(+), 45 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 4b934420..4b84e967 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
 1.0.0
 -----
+ * Add metric to report consistency check duration (CASSSIDECAR-165)
  * Add mTLS Authentication in Sidecar (CASSANDRASC-156)
  * Fix dangling restore jobs (CASSANDRASC-155)
  * Remove duplicated AbstractSchema class (CASSANDRASC-154)
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/AccessControlConfigurationImpl.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/AccessControlConfigurationImpl.java
index ac58f560..a578396d 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/AccessControlConfigurationImpl.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/AccessControlConfigurationImpl.java
@@ -67,7 +67,7 @@ public class AccessControlConfigurationImpl implements 
AccessControlConfiguratio
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     @Override
     @JsonProperty
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/metrics/NamedMetric.java 
b/server/src/main/java/org/apache/cassandra/sidecar/metrics/NamedMetric.java
index e5966253..6ceb657e 100644
--- a/server/src/main/java/org/apache/cassandra/sidecar/metrics/NamedMetric.java
+++ b/server/src/main/java/org/apache/cassandra/sidecar/metrics/NamedMetric.java
@@ -59,8 +59,12 @@ public class NamedMetric<T extends Metric>
         private final Function<String, T> metricCreator;
         private final List<Tag> tags = new ArrayList<>();
         private String domain;
-        private String name;
+        private String simpleName;
 
+        /**
+         * Construct the build with the function to create metric
+         * @param metricCreator function to create metric from the canonical 
name, which consists of the domain, tags and the simple name.
+         */
         public Builder(Function<String, T> metricCreator)
         {
             this.metricCreator = metricCreator;
@@ -78,14 +82,14 @@ public class NamedMetric<T extends Metric>
         }
 
         /**
-         * Sets {@code name} of metric.
+         * Sets the simple {@code name} of metric.
          *
-         * @param name metric name
+         * @param simpleName simply metric name
          * @return a reference to this Builder
          */
-        public Builder<T> withName(String name)
+        public Builder<T> withName(String simpleName)
         {
-            return update(b -> b.name = name);
+            return update(b -> b.simpleName = simpleName);
         }
 
         /**
@@ -124,7 +128,7 @@ public class NamedMetric<T extends Metric>
         {
             Objects.requireNonNull(metricCreator);
             Objects.requireNonNull(domain);
-            Objects.requireNonNull(name);
+            Objects.requireNonNull(simpleName);
 
             return new NamedMetric<>(this);
         }
@@ -133,7 +137,7 @@ public class NamedMetric<T extends Metric>
         {
             String domainPart = domain + '.';
             String combinedTags = !tags.isEmpty() ? combineTags() + '.' : "";
-            return domainPart + combinedTags + name;
+            return domainPart + combinedTags + simpleName;
         }
 
         private String combineTags()
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/metrics/RestoreMetrics.java 
b/server/src/main/java/org/apache/cassandra/sidecar/metrics/RestoreMetrics.java
index 2e845493..ba07169c 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/metrics/RestoreMetrics.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/metrics/RestoreMetrics.java
@@ -19,8 +19,10 @@
 package org.apache.cassandra.sidecar.metrics;
 
 import java.util.Objects;
+import java.util.function.Function;
 
 import com.codahale.metrics.DefaultSettableGauge;
+import com.codahale.metrics.Metric;
 import com.codahale.metrics.MetricRegistry;
 import com.codahale.metrics.Timer;
 
@@ -35,6 +37,7 @@ public class RestoreMetrics
     protected final MetricRegistry metricRegistry;
     public final NamedMetric<Timer> sliceReplicationTime;
     public final NamedMetric<Timer> jobCompletionTime;
+    public final NamedMetric<Timer> consistencyCheckTime;
     public final NamedMetric<DeltaGauge> successfulJobs;
     public final NamedMetric<DeltaGauge> failedJobs;
     public final NamedMetric<DefaultSettableGauge<Integer>> activeJobs;
@@ -46,39 +49,22 @@ public class RestoreMetrics
     {
         this.metricRegistry = Objects.requireNonNull(metricRegistry, "Metric 
registry can not be null");
 
-        sliceReplicationTime
-        = 
NamedMetric.builder(metricRegistry::timer).withDomain(DOMAIN).withName("SliceReplicationTime").build();
-        jobCompletionTime
-        = 
NamedMetric.builder(metricRegistry::timer).withDomain(DOMAIN).withName("JobCompletionTime").build();
-        successfulJobs
-        = NamedMetric.builder(name -> metricRegistry.gauge(name, 
DeltaGauge::new))
-                     .withDomain(DOMAIN)
-                     .withName("SuccessfulJobs")
-                     .build();
-        failedJobs
-        = NamedMetric.builder(name -> metricRegistry.gauge(name, 
DeltaGauge::new))
-                     .withDomain(DOMAIN)
-                     .withName("FailedJobs")
-                     .build();
-        activeJobs
-        = NamedMetric.builder(name -> metricRegistry.gauge(name, () -> new 
DefaultSettableGauge<>(0)))
-                     .withDomain(DOMAIN)
-                     .withName("ActiveJobs")
-                     .build();
-        tokenRefreshed
-        = NamedMetric.builder(name -> metricRegistry.gauge(name, 
DeltaGauge::new))
-                     .withDomain(DOMAIN)
-                     .withName("TokenRefreshed")
-                     .build();
-        tokenUnauthorized
-        = NamedMetric.builder(name -> metricRegistry.gauge(name, 
DeltaGauge::new))
-                     .withDomain(DOMAIN)
-                     .withName("TokenUnauthorized")
-                     .build();
-        tokenExpired
-        = NamedMetric.builder(name -> metricRegistry.gauge(name, 
DeltaGauge::new))
-                     .withDomain(DOMAIN)
-                     .withName("TokenExpired")
-                     .build();
+        sliceReplicationTime = createMetric("SliceReplicationTime", 
metricRegistry::timer);
+        jobCompletionTime = createMetric("JobCompletionTime", 
metricRegistry::timer);
+        consistencyCheckTime = createMetric("ConsistencyCheckTime", 
metricRegistry::timer);
+        successfulJobs = createMetric("SuccessfulJobs", name -> 
metricRegistry.gauge(name, DeltaGauge::new));
+        failedJobs = createMetric("FailedJobs", name -> 
metricRegistry.gauge(name, DeltaGauge::new));
+        activeJobs = createMetric("ActiveJobs", name -> 
metricRegistry.gauge(name, () -> new DefaultSettableGauge<>(0)));
+        tokenRefreshed = createMetric("TokenRefreshed", name -> 
metricRegistry.gauge(name, DeltaGauge::new));
+        tokenUnauthorized = createMetric("TokenUnauthorized", name -> 
metricRegistry.gauge(name, DeltaGauge::new));
+        tokenExpired = createMetric("TokenExpired",  name -> 
metricRegistry.gauge(name, DeltaGauge::new));
+    }
+
+    private <T extends Metric> NamedMetric<T> createMetric(String simpleName, 
Function<String, T> metricCreator)
+    {
+        return NamedMetric.builder(metricCreator)
+                          .withDomain(DOMAIN)
+                          .withName(simpleName)
+                          .build();
     }
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobConsistencyLevelChecker.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobConsistencyLevelChecker.java
index 47e67763..637e97d9 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobConsistencyLevelChecker.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobConsistencyLevelChecker.java
@@ -24,6 +24,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,6 +49,9 @@ import 
org.apache.cassandra.sidecar.concurrent.TaskExecutorPool;
 import org.apache.cassandra.sidecar.db.RestoreJob;
 import org.apache.cassandra.sidecar.db.RestoreRange;
 import org.apache.cassandra.sidecar.db.RestoreRangeDatabaseAccessor;
+import org.apache.cassandra.sidecar.metrics.RestoreMetrics;
+import org.apache.cassandra.sidecar.metrics.SidecarMetrics;
+import org.apache.cassandra.sidecar.metrics.StopWatch;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.VisibleForTesting;
 
@@ -67,18 +71,21 @@ public class RestoreJobConsistencyLevelChecker
     private final RestoreJobDiscoverer restoreJobDiscoverer;
     private final RestoreRangeDatabaseAccessor rangeDatabaseAccessor;
     private final TaskExecutorPool taskExecutorPool;
+    private final RestoreMetrics restoreMetrics;
     private volatile boolean firstTimeSinceImportReady = true;
 
     @Inject
     public RestoreJobConsistencyLevelChecker(RingTopologyRefresher 
ringTopologyRefresher,
                                              RestoreJobDiscoverer 
restoreJobDiscoverer,
                                              RestoreRangeDatabaseAccessor 
rangeDatabaseAccessor,
-                                             ExecutorPools executorPools)
+                                             ExecutorPools executorPools,
+                                             SidecarMetrics sidecarMetrics)
     {
         this.ringTopologyRefresher = ringTopologyRefresher;
         this.restoreJobDiscoverer = restoreJobDiscoverer;
         this.rangeDatabaseAccessor = rangeDatabaseAccessor;
         this.taskExecutorPool = executorPools.internal();
+        this.restoreMetrics = sidecarMetrics.server().restore();
     }
 
     public Future<RestoreJobProgress> check(RestoreJob restoreJob, 
RestoreJobProgressFetchPolicy fetchPolicy)
@@ -90,8 +97,10 @@ public class RestoreJobConsistencyLevelChecker
         RestoreJobProgressCollector collector = 
RestoreJobProgressCollectors.create(restoreJob, fetchPolicy);
         RestoreRangeStatus successCriteria = 
restoreJob.expectedNextRangeStatus();
         ConsistencyVerifier verifier = 
ConsistencyVerifiers.forConsistencyLevel(restoreJob.consistencyLevel, 
restoreJob.localDatacenter);
-        return ringTopologyRefresher.replicaByTokenRangeAsync(restoreJob)
-                                    .compose(topology -> 
findRangesAndConclude(restoreJob, successCriteria, topology, verifier, 
collector));
+        Future<RestoreJobProgress> future = ringTopologyRefresher
+                                            
.replicaByTokenRangeAsync(restoreJob)
+                                            .compose(topology -> 
findRangesAndConclude(restoreJob, successCriteria, topology, verifier, 
collector));
+        return StopWatch.measureTimeTaken(future, durationNanos -> 
restoreMetrics.consistencyCheckTime.metric.update(durationNanos, 
TimeUnit.NANOSECONDS));
     }
 
     private Future<RestoreJobProgress> findRangesAndConclude(RestoreJob 
restoreJob,
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/routes/restore/BaseRestoreJobTests.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/routes/restore/BaseRestoreJobTests.java
index 45742674..50dc2c3c 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/routes/restore/BaseRestoreJobTests.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/routes/restore/BaseRestoreJobTests.java
@@ -69,6 +69,7 @@ import 
org.apache.cassandra.sidecar.db.RestoreSliceDatabaseAccessor;
 import org.apache.cassandra.sidecar.db.schema.SidecarSchema;
 import org.apache.cassandra.sidecar.exceptions.RestoreJobFatalException;
 import org.apache.cassandra.sidecar.foundation.RestoreJobSecretsGen;
+import org.apache.cassandra.sidecar.metrics.SidecarMetrics;
 import org.apache.cassandra.sidecar.restore.RestoreJobDiscoverer;
 import org.apache.cassandra.sidecar.restore.RestoreJobManagerGroup;
 import org.apache.cassandra.sidecar.restore.RestoreJobProgressTracker;
@@ -98,6 +99,7 @@ public abstract class BaseRestoreJobTests
     protected Vertx vertx;
     protected Server server;
     protected WebClient client;
+    protected SidecarMetrics sidecarMetrics;
     protected TestRestoreJobDatabaseAccessor testRestoreJobs;
     protected TestRestoreSliceDatabaseAccessor testRestoreSlices;
     protected TestRestoreRangeDatabaseAccessor testRestoreRanges;
@@ -114,6 +116,7 @@ public abstract class BaseRestoreJobTests
                                                                      .with(new 
TestModuleOverride())));
         vertx = injector.getInstance(Vertx.class);
         server = injector.getInstance(Server.class);
+        sidecarMetrics = injector.getInstance(SidecarMetrics.class);
         client = WebClient.create(vertx, new WebClientOptions());
         testRestoreJobs = (TestRestoreJobDatabaseAccessor) 
injector.getInstance(RestoreJobDatabaseAccessor.class);
         testRestoreSlices = (TestRestoreSliceDatabaseAccessor) 
injector.getInstance(RestoreSliceDatabaseAccessor.class);
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/routes/restore/RestoreJobProgressHandlerTest.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/routes/restore/RestoreJobProgressHandlerTest.java
index b478f134..0ade5dc9 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/routes/restore/RestoreJobProgressHandlerTest.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/routes/restore/RestoreJobProgressHandlerTest.java
@@ -87,6 +87,7 @@ class RestoreJobProgressHandlerTest extends 
BaseRestoreJobTests
                         asyncResult -> {
                             RestoreJobProgressResponsePayload respBody = 
assertOKResponseAndExtractBody(asyncResult);
                             assertPendingProgressRespBody(respBody);
+                            
assertThat(sidecarMetrics.server().restore().consistencyCheckTime.metric.getSnapshot().getValues()).hasSize(1);
                         });
     }
 
@@ -159,6 +160,7 @@ class RestoreJobProgressHandlerTest extends 
BaseRestoreJobTests
                             assertThat(respBody.abortedRanges()).isNull();
                             // retrieving all 2 ranges back
                             assertThat(rangesRetrieved).isEqualTo(2);
+                            
assertThat(sidecarMetrics.server().restore().consistencyCheckTime.metric.getSnapshot().getValues()).hasSize(1);
                         });
     }
 
@@ -183,6 +185,7 @@ class RestoreJobProgressHandlerTest extends 
BaseRestoreJobTests
                             assertThat(respBody.abortedRanges()).isNull();
                             // retrieving all 2 ranges back, while there are 3 
ranges in total. One range is satisfied
                             assertThat(rangesRetrieved).isEqualTo(2);
+                            
assertThat(sidecarMetrics.server().restore().consistencyCheckTime.metric.getSnapshot().getValues()).hasSize(1);
                         });
     }
 


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

Reply via email to