Firefly: send to flow destination and optional collector#8040
Firefly: send to flow destination and optional collector#8040kofemann merged 2 commits intodCache:11.2from
Conversation
Signed-off-by: Shawn McKee <smckee@umich.edu>
There was a problem hiding this comment.
Pull request overview
Updates pool “firefly” UDP marker sending so the default behavior (send to transfer flow destination/UDP 10514) remains unchanged while allowing an optional second copy to be sent to a separately configured collector.
Changes:
- Add an optional “collector” destination and send firefly markers to both primary destination and collector (when configured and different).
- Keep the primary destination logic unchanged; avoid sending a duplicate when collector equals primary.
- Update
pool.firefly.destinationdocumentation to describe the new “additional collector copy” behavior and provide examples.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
modules/dcache/src/main/java/org/dcache/pool/movers/TransferLifeCycle.java |
Adds optional collector destination and routes start/end markers to primary + optional collector. |
skel/share/defaults/pool.properties |
Updates property comments to document new pool.firefly.destination semantics and examples. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
modules/dcache/src/main/java/org/dcache/pool/movers/TransferLifeCycle.java
Show resolved
Hide resolved
| * Send flow marker to the primary destination and optional configured collector. | ||
| * | ||
| * @param primaryDst Primary destination (based on flow/peer) | ||
| * @param payload the marker | ||
| */ | ||
| private void sendToMultipleDestinations(InetSocketAddress primaryDst, @Nonnull String payload) { | ||
| // Send to primary destination | ||
| send(primaryDst, payload); | ||
|
|
||
| // Send to collector if configured and different from primary | ||
| if (fireflyCollector != null && !fireflyCollector.equals(primaryDst)) { | ||
| send(fireflyCollector, payload); |
There was a problem hiding this comment.
With the new dual-send behavior, sendToMultipleDestinations may call send twice per marker, and send currently creates a new DatagramSocket each time. When a collector is configured, this doubles socket creation overhead for every start/end marker. Consider reusing a single socket per marker (send to primary and collector from the same socket) to reduce per-transfer overhead.
| * Send flow marker to the primary destination and optional configured collector. | |
| * | |
| * @param primaryDst Primary destination (based on flow/peer) | |
| * @param payload the marker | |
| */ | |
| private void sendToMultipleDestinations(InetSocketAddress primaryDst, @Nonnull String payload) { | |
| // Send to primary destination | |
| send(primaryDst, payload); | |
| // Send to collector if configured and different from primary | |
| if (fireflyCollector != null && !fireflyCollector.equals(primaryDst)) { | |
| send(fireflyCollector, payload); | |
| * Send flow marker using an existing datagram socket. | |
| * | |
| * @param socket Datagram socket to use for sending. | |
| * @param dst Inet address where the flow marker should be sent. | |
| * @param payload the marker | |
| * @throws IllegalStateException if flow marker ist not build. | |
| */ | |
| private void send(DatagramSocket socket, InetSocketAddress dst, @Nonnull String payload) | |
| throws IllegalStateException { | |
| byte[] data = payload.getBytes(StandardCharsets.UTF_8); | |
| DatagramPacket p = new DatagramPacket(data, data.length, dst); | |
| try { | |
| socket.send(p); | |
| } catch (IOException e) { | |
| LOGGER.warn("Failed to send flow marker to {}: {}", dst, e.getMessage()); | |
| } | |
| } | |
| /** | |
| * Send flow marker to the primary destination and optional configured collector. | |
| * | |
| * @param primaryDst Primary destination (based on flow/peer) | |
| * @param payload the marker | |
| */ | |
| private void sendToMultipleDestinations(InetSocketAddress primaryDst, @Nonnull String payload) { | |
| try (DatagramSocket socket = new DatagramSocket()) { | |
| // Send to primary destination | |
| send(socket, primaryDst, payload); | |
| // Send to collector if configured and different from primary | |
| if (fireflyCollector != null && !fireflyCollector.equals(primaryDst)) { | |
| send(socket, fireflyCollector, payload); | |
| } | |
| } catch (IOException e) { | |
| LOGGER.warn("Failed to send flow marker: {}", e.getMessage()); |
| private Predicate<InetAddress> localSubnet = a -> false; | ||
|
|
||
| // optional additional collector destination for firefly markers | ||
| private InetSocketAddress fireflyCollector = null; |
There was a problem hiding this comment.
null is default initializer
| * If no port is provided, the default firefly UDP port (10514) is used. | ||
| */ | ||
| public void setFireflyDestination(String addr) { | ||
| fireflyCollector = null; |
modules/dcache/src/main/java/org/dcache/pool/movers/TransferLifeCycle.java
Show resolved
Hide resolved
- Drop redundant '= null' field initializer - Remove unused Strings import; use addr.isBlank() instead - Extend setFireflyDestination Javadoc with IPv6 bracket format examples - Reuse single DatagramSocket for primary + collector sends Signed-off-by: Shawn McKee <smckee@umich.edu>
ShawnMcKee
left a comment
There was a problem hiding this comment.
Thanks for the suggestions! Addressed all comments in commit 9f4b114ed6:
fireflyCollector = null— dropped the explicit= nullfield initializer (default for object references).fireflyCollector = null;inside setter — removed the redundant reset line at the top ofsetFireflyDestination.- Blank-string guard — replaced
Strings.isNullOrEmpty(addr)withaddr != null && !addr.isBlank()to correctly handle whitespace-only strings; also removed the now-unusedStringsimport. - IPv6 Javadoc — added
[ipv6-address]and[ipv6-address]:portas documented accepted formats, with a note that the bracketed form is required byHostAndPort.fromStringwhen a port is present. - Socket reuse — refactored
sendto accept a caller-suppliedDatagramSocket;sendToMultipleDestinationsnow opens one socket and uses it for both the primary and collector sends, halving socket creation overhead when a collector is configured.
DmitryLitvintsev
left a comment
There was a problem hiding this comment.
Looks good to me. I will also wait for our colleagues in Europe to have a look as well tomorrow.
|
@ShawnMcKee, thanks for the contribution. |
|
The PR is against 11.2. Will the update to master contain the same changes or should I cherry-pick them myself? |
|
Can you cherry-pick them? Then we can delete the branch. |
Summary
This PR updates firefly sending semantics to use existing configuration variables while preserving default behavior.
pool.enable.firefly=true: continue sending fireflies to the transfer flow destination (UDP 10514).pool.firefly.destinationunset: no extra copy is sent.pool.firefly.destinationset: send one additional copy to that destination.The configured
pool.firefly.destinationaccepts:host(defaults to UDP 10514)host:port(explicit port override)Code changes
modules/dcache/src/main/java/org/dcache/pool/movers/TransferLifeCycle.javasetFireflyDestinationsemantics and accepted formats.skel/share/defaults/pool.propertiespool.firefly.destinationto describe new behavior and examples.Build validation
Executed:
mvn -pl modules/dcache -am -DskipTests compilemvn -pl modules/dcache -am -DskipTests packageResult:
Runtime validation (UMFS19 + dcdum01)
Deployed updated
dcache-core-11.2.1.jaronumfs19and restarted:dcache@umfs19Domain_1.serviceactivedcache@umfs19Domain_2.serviceactiveRuntime config used:
pool.enable.firefly=truepool.firefly.destination=firefly-collector.cern.chDeterministic protocol tests:
scitag.flow=313SciTag: 313Capture (
/tmp/firefly-collector-test.pcap) showed destinations:2001:48a8:68f7:1:192:41:231:128:105142001:1458:301:86::100:8:10514(firefly-collector.cern.ch)Counts by protocol/state (aggregated across both destinations):
xrootd start: 2xrootd end: 2https start: 2https end: 2Per destination each protocol/state appeared exactly once, confirming dual-send: