Skip to content

Commit 76205dd

Browse files
committed
drv: add gRPC request statistics
``` [zit] (pool_write@dCacheDomain) admin > osm show stats CTA gRPC Requests statistics average±stderr(ms) min(ms) max(ms) STD(ms) Samples Period CANCEL_FLUSH 23.50± 12.50 11 36 17.68 2 42 s CANCEL_STAGE 13.00± NaN 13 13 NaN 1 26 s GET_ARCHIVE_ID 7.00± NaN 7 7 NaN 1 42 s SUBMIT_STAGE 23.00± NaN 23 23 NaN 1 42 s CTA gRPC Requests counters requests failed CANCEL_FLUSH 3 0 CANCEL_STAGE 1 0 GET_ARCHIVE_ID 2 0 Total 6 0 [zit] (pool_write@dCacheDomain) admin > osm show requests Pending requests: FLUSH: count: 1 000087C50D356F8348B5B806CCB31442384A -> ArchiveRequest-Frontend-zitcta-ts01-3179918-20250604-15:30:05-0-176 STAGE: count: 1 000025BF54F7EC7C4E3A8F03E510EB3F1971 -> RetrieveRequest-Frontend-zitcta-ts01-3179918-20250604-15:30:05-0-177 ```
1 parent f60009b commit 76205dd

1 file changed

Lines changed: 82 additions & 6 deletions

File tree

src/main/java/org/dcache/nearline/cta/CtaNearlineStorage.java

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,21 @@
33
import static com.google.common.base.Preconditions.checkArgument;
44

55
import ch.cern.cta.rpc.CtaRpcGrpc;
6+
import ch.cern.cta.rpc.Response;
67
import com.google.common.annotations.VisibleForTesting;
78
import com.google.common.base.Splitter;
89
import com.google.common.base.Throwables;
910
import com.google.common.net.HostAndPort;
1011
import com.google.common.util.concurrent.ThreadFactoryBuilder;
1112
import diskCacheV111.util.CacheException;
1213
import dmg.util.command.Command;
14+
import dmg.util.command.Option;
1315
import io.grpc.ChannelCredentials;
1416
import io.grpc.ConnectivityState;
1517
import io.grpc.Deadline;
1618
import io.grpc.InsecureChannelCredentials;
1719
import io.grpc.ManagedChannel;
20+
import io.grpc.Status;
1821
import io.grpc.StatusRuntimeException;
1922
import io.grpc.TlsChannelCredentials;
2023
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
@@ -37,6 +40,8 @@
3740
import java.util.stream.Collectors;
3841

3942
import ch.cern.cta.rpc.CtaRpcGrpc.CtaRpcBlockingStub;
43+
import org.dcache.commons.stats.RequestCounters;
44+
import org.dcache.commons.stats.RequestExecutionTimeGauges;
4045
import org.dcache.namespace.FileAttribute;
4146
import org.dcache.nearline.cta.xrootd.DataMover;
4247
import org.dcache.pool.nearline.spi.FlushRequest;
@@ -138,6 +143,29 @@ public class CtaNearlineStorage implements NearlineStorage {
138143
*/
139144
private boolean dio;
140145

146+
147+
/**
148+
* Actions that can be performed by this nearline storage. A shorthand version of cta.eos.CtaEos.Workflow.EventType
149+
*/
150+
enum Action {
151+
GET_ARCHIVE_ID,
152+
SUBMIT_FLUSH,
153+
SUBMIT_STAGE,
154+
CANCEL_FLUSH,
155+
CANCEL_STAGE,
156+
DELETE_REQUEST,
157+
}
158+
159+
/**
160+
* gRPC request execution statistics
161+
*/
162+
private final RequestExecutionTimeGauges<Action> requestStats = new RequestExecutionTimeGauges<>("CTA gRPC Requests statistics");
163+
164+
/**
165+
* gRPC request counters
166+
*/
167+
private final RequestCounters<Action> requestCounters = new RequestCounters<>("CTA gRPC Requests counters");
168+
141169
public CtaNearlineStorage(String type, String name) {
142170

143171
Objects.requireNonNull(type, "HSM type is not provided");
@@ -187,7 +215,7 @@ public void flush(Iterable<FlushRequest> requests) {
187215
}
188216

189217
var createRequest = ctaRequestFactory.getCreateRequest(fr.getFileAttributes());
190-
var createResponse = cta.withDeadline(getRequestDeadline()).create(createRequest);
218+
var createResponse = withStats(Action.GET_ARCHIVE_ID, () -> cta.withDeadline(getRequestDeadline()).create(createRequest));
191219
LOGGER.info("{}: Create new archive id {} for {}", fr.getId(),
192220
createResponse.getArchiveFileId(),
193221
fr.getFileAttributes().getPnfsId()
@@ -240,7 +268,7 @@ public void completed(Set<URI> uris) {
240268
};
241269

242270
var ar = ctaRequestFactory.getStoreRequest(r, ctaArchiveId);
243-
var response = cta.withDeadline(getRequestDeadline()).archive(ar);
271+
var response = withStats(Action.CANCEL_FLUSH, () -> cta.withDeadline(getRequestDeadline()).archive(ar));
244272

245273
LOGGER.info("{} : {} : archive id {}, request: {}",
246274
r.getId(),
@@ -256,7 +284,7 @@ public void completed(Set<URI> uris) {
256284
@Override
257285
public void cancel() {
258286
try {
259-
cta.withDeadline(getRequestDeadline()).delete(cancelRequest);
287+
withStats(Action.CANCEL_FLUSH, () -> cta.withDeadline(getRequestDeadline()).delete(cancelRequest));
260288
super.cancel();
261289
} catch (StatusRuntimeException e) {
262290
LOGGER.error("Failed to cancel flush request: {}", e.getMessage());
@@ -313,7 +341,7 @@ public void completed(Set<Checksum> checksums) {
313341
}
314342

315343
var rr = ctaRequestFactory.getStageRequest(r);
316-
var response = cta.withDeadline(getRequestDeadline()).retrieve(rr);
344+
var response = withStats(Action.SUBMIT_STAGE, () -> cta.withDeadline(getRequestDeadline()).retrieve(rr));
317345
LOGGER.info("{} : {} : request: {}",
318346
r.getId(),
319347
r.getFileAttributes().getPnfsId(),
@@ -326,7 +354,7 @@ public void completed(Set<Checksum> checksums) {
326354
public void cancel() {
327355
// on cancel send the request to CTA; on success cancel the requests
328356
try {
329-
cta.withDeadline(getRequestDeadline()).cancelRetrieve(cancelRequest);
357+
withStats(Action.CANCEL_STAGE, () -> cta.withDeadline(getRequestDeadline()).cancelRetrieve(cancelRequest));
330358
super.cancel();
331359
} catch (StatusRuntimeException e) {
332360
LOGGER.error("Failed to cancel retrieve request: {}", e.getMessage());
@@ -362,7 +390,7 @@ public void remove(Iterable<RemoveRequest> requests) {
362390

363391
try {
364392
var deleteRequest = ctaRequestFactory.getRemoveRequest(r);
365-
var result = cta.withDeadline(getRequestDeadline()).delete(deleteRequest);
393+
var result = withStats(Action.DELETE_REQUEST, () -> cta.withDeadline(getRequestDeadline()).delete(deleteRequest));
366394
LOGGER.info("Delete request {} submitted {}",
367395
r.getId(),
368396
r.getUri()
@@ -576,4 +604,52 @@ public String call() {
576604
return sb.toString();
577605
}
578606
}
607+
608+
609+
/**
610+
* Wraps a gRPC request with statistics collection.
611+
*
612+
* @param action the action type for which the statistics are collected.
613+
* @param callable the gRPC request to execute.
614+
* @return the response from the gRPC request.
615+
* @throws Exception if the gRPC request fails.
616+
*/
617+
private Response withStats(Action action, Callable<Response> callable) throws StatusRuntimeException {
618+
try {
619+
var t0 = System.nanoTime();
620+
var response = callable.call();
621+
requestStats.getGauge(action).update(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t0));
622+
requestCounters.incrementRequests(action);
623+
624+
return response;
625+
} catch (Exception e) {
626+
requestCounters.incrementFailed(action);
627+
Throwables.throwIfInstanceOf(e, StatusRuntimeException.class);
628+
throw new StatusRuntimeException(Status.UNKNOWN);
629+
}
630+
}
631+
632+
633+
@Command(name="show stats",
634+
hint = "show gRPC requests statistics",
635+
description = "Show gRPC requests statistics for CTA nearline storage")
636+
public class StatsCommand implements Callable<String> {
637+
638+
@Option(name = "c", usage = "clear current statistics values")
639+
boolean clean;
640+
641+
@Override
642+
public String call() {
643+
StringBuilder sb = new StringBuilder();
644+
sb.append(requestStats);
645+
sb.append("\n\n");
646+
sb.append(requestCounters);
647+
648+
if (clean) {
649+
requestStats.reset();
650+
requestCounters.reset();
651+
}
652+
return sb.toString();
653+
}
654+
}
579655
}

0 commit comments

Comments
 (0)