From 551927698543d8ac4cc8606bb1e4d3bfa3ed6c58 Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Fri, 9 Aug 2024 14:15:08 +0200 Subject: [PATCH 01/33] Add reliability to NetworkMessage --- commons/zenoh-codec/src/network/mod.rs | 4 ++- commons/zenoh-protocol/src/network/mod.rs | 7 ++-- commons/zenoh-protocol/src/transport/frame.rs | 3 +- zenoh/src/net/primitives/mux.rs | 33 +++++++++++++++++-- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/commons/zenoh-codec/src/network/mod.rs b/commons/zenoh-codec/src/network/mod.rs index c68a3470aa..65c75f1452 100644 --- a/commons/zenoh-codec/src/network/mod.rs +++ b/commons/zenoh-codec/src/network/mod.rs @@ -76,7 +76,9 @@ where let header: u8 = self.codec.read(&mut *reader)?; let codec = Zenoh080Header::new(header); - codec.read(&mut *reader) + let mut msg: NetworkMessage = codec.read(&mut *reader)?; + msg.reliability = self.reliability; + Ok(msg) } } diff --git a/commons/zenoh-protocol/src/network/mod.rs b/commons/zenoh-protocol/src/network/mod.rs index 407df6dd52..336f952f3d 100644 --- a/commons/zenoh-protocol/src/network/mod.rs +++ b/commons/zenoh-protocol/src/network/mod.rs @@ -30,7 +30,7 @@ pub use push::Push; pub use request::{AtomicRequestId, Request, RequestId}; pub use response::{Response, ResponseFinal}; -use crate::core::{CongestionControl, Priority}; +use crate::core::{CongestionControl, Priority, Reliability}; pub mod id { // WARNING: it's crucial that these IDs do NOT collide with the IDs @@ -83,6 +83,7 @@ pub enum NetworkBody { #[derive(Debug, Clone, PartialEq, Eq)] pub struct NetworkMessage { pub body: NetworkBody, + pub reliability: Reliability, #[cfg(feature = "stats")] pub size: Option, } @@ -109,8 +110,7 @@ impl NetworkMessage { #[inline] pub fn is_reliable(&self) -> bool { - // TODO - true + self.reliability == Reliability::Reliable } #[inline] @@ -179,6 +179,7 @@ impl From for NetworkMessage { fn from(body: NetworkBody) -> Self { Self { body, + reliability: Reliability::DEFAULT, #[cfg(feature = "stats")] size: None, } diff --git a/commons/zenoh-protocol/src/transport/frame.rs b/commons/zenoh-protocol/src/transport/frame.rs index b3ef1d819f..10e55cc99e 100644 --- a/commons/zenoh-protocol/src/transport/frame.rs +++ b/commons/zenoh-protocol/src/transport/frame.rs @@ -95,7 +95,8 @@ impl Frame { let ext_qos = ext::QoSType::rand(); let mut payload = vec![]; for _ in 0..rng.gen_range(1..4) { - let m = NetworkMessage::rand(); + let mut m = NetworkMessage::rand(); + m.reliability = reliability; payload.push(m); } diff --git a/zenoh/src/net/primitives/mux.rs b/zenoh/src/net/primitives/mux.rs index bc718ba324..b017e3858a 100644 --- a/zenoh/src/net/primitives/mux.rs +++ b/zenoh/src/net/primitives/mux.rs @@ -13,9 +13,12 @@ // use std::sync::OnceLock; -use zenoh_protocol::network::{ - interest::Interest, Declare, NetworkBody, NetworkMessage, Push, Request, Response, - ResponseFinal, +use zenoh_protocol::{ + core::Reliability, + network::{ + interest::Interest, Declare, NetworkBody, NetworkMessage, Push, Request, Response, + ResponseFinal, + }, }; use zenoh_transport::{multicast::TransportMulticast, unicast::TransportUnicast}; @@ -46,6 +49,7 @@ impl Primitives for Mux { fn send_interest(&self, msg: Interest) { let msg = NetworkMessage { body: NetworkBody::Interest(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -74,6 +78,7 @@ impl Primitives for Mux { fn send_declare(&self, msg: Declare) { let msg = NetworkMessage { body: NetworkBody::Declare(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -98,6 +103,7 @@ impl Primitives for Mux { fn send_push(&self, msg: Push) { let msg = NetworkMessage { body: NetworkBody::Push(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -122,6 +128,7 @@ impl Primitives for Mux { fn send_request(&self, msg: Request) { let msg = NetworkMessage { body: NetworkBody::Request(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -146,6 +153,7 @@ impl Primitives for Mux { fn send_response(&self, msg: Response) { let msg = NetworkMessage { body: NetworkBody::Response(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -170,6 +178,7 @@ impl Primitives for Mux { fn send_response_final(&self, msg: ResponseFinal) { let msg = NetworkMessage { body: NetworkBody::ResponseFinal(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -201,6 +210,7 @@ impl EPrimitives for Mux { let ctx = RoutingContext { msg: NetworkMessage { body: NetworkBody::Interest(ctx.msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }, @@ -226,6 +236,7 @@ impl EPrimitives for Mux { let ctx = RoutingContext { msg: NetworkMessage { body: NetworkBody::Declare(ctx.msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }, @@ -250,6 +261,7 @@ impl EPrimitives for Mux { fn send_push(&self, msg: Push) { let msg = NetworkMessage { body: NetworkBody::Push(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -274,6 +286,7 @@ impl EPrimitives for Mux { fn send_request(&self, msg: Request) { let msg = NetworkMessage { body: NetworkBody::Request(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -298,6 +311,7 @@ impl EPrimitives for Mux { fn send_response(&self, msg: Response) { let msg = NetworkMessage { body: NetworkBody::Response(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -322,6 +336,7 @@ impl EPrimitives for Mux { fn send_response_final(&self, msg: ResponseFinal) { let msg = NetworkMessage { body: NetworkBody::ResponseFinal(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -368,6 +383,7 @@ impl Primitives for McastMux { fn send_interest(&self, msg: Interest) { let msg = NetworkMessage { body: NetworkBody::Interest(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -392,6 +408,7 @@ impl Primitives for McastMux { fn send_declare(&self, msg: Declare) { let msg = NetworkMessage { body: NetworkBody::Declare(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -416,6 +433,7 @@ impl Primitives for McastMux { fn send_push(&self, msg: Push) { let msg = NetworkMessage { body: NetworkBody::Push(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -440,6 +458,7 @@ impl Primitives for McastMux { fn send_request(&self, msg: Request) { let msg = NetworkMessage { body: NetworkBody::Request(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -464,6 +483,7 @@ impl Primitives for McastMux { fn send_response(&self, msg: Response) { let msg = NetworkMessage { body: NetworkBody::Response(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -488,6 +508,7 @@ impl Primitives for McastMux { fn send_response_final(&self, msg: ResponseFinal) { let msg = NetworkMessage { body: NetworkBody::ResponseFinal(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -519,6 +540,7 @@ impl EPrimitives for McastMux { let ctx = RoutingContext { msg: NetworkMessage { body: NetworkBody::Interest(ctx.msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }, @@ -544,6 +566,7 @@ impl EPrimitives for McastMux { let ctx = RoutingContext { msg: NetworkMessage { body: NetworkBody::Declare(ctx.msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }, @@ -568,6 +591,7 @@ impl EPrimitives for McastMux { fn send_push(&self, msg: Push) { let msg = NetworkMessage { body: NetworkBody::Push(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -592,6 +616,7 @@ impl EPrimitives for McastMux { fn send_request(&self, msg: Request) { let msg = NetworkMessage { body: NetworkBody::Request(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -616,6 +641,7 @@ impl EPrimitives for McastMux { fn send_response(&self, msg: Response) { let msg = NetworkMessage { body: NetworkBody::Response(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; @@ -640,6 +666,7 @@ impl EPrimitives for McastMux { fn send_response_final(&self, msg: ResponseFinal) { let msg = NetworkMessage { body: NetworkBody::ResponseFinal(msg), + reliability: Reliability::Reliable, #[cfg(feature = "stats")] size: None, }; From ef76d115cdbc0a5b5f79d70d89327eb891c18f55 Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Fri, 9 Aug 2024 14:50:20 +0200 Subject: [PATCH 02/33] Updates --- commons/zenoh-codec/src/transport/batch.rs | 13 ++++++------- io/zenoh-transport/src/common/pipeline.rs | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/commons/zenoh-codec/src/transport/batch.rs b/commons/zenoh-codec/src/transport/batch.rs index bfdc21f618..d4fd603864 100644 --- a/commons/zenoh-codec/src/transport/batch.rs +++ b/commons/zenoh-codec/src/transport/batch.rs @@ -150,13 +150,12 @@ where fn write(self, writer: &mut W, x: (&NetworkMessage, &FrameHeader)) -> Self::Output { let (m, f) = x; - // @TODO: m.is_reliable() always return true for the time being - // if let (Reliability::Reliable, false) | (Reliability::BestEffort, true) = - // (f.reliability, m.is_reliable()) - // { - // // We are not serializing on the right frame. - // return Err(BatchError::NewFrame); - // } + if let (Reliability::Reliable, false) | (Reliability::BestEffort, true) = + (f.reliability, m.is_reliable()) + { + // We are not serializing on the right frame. + return Err(BatchError::NewFrame); + } // Mark the write operation let mark = writer.mark(); diff --git a/io/zenoh-transport/src/common/pipeline.rs b/io/zenoh-transport/src/common/pipeline.rs index 68a4b87d24..9cf8d85843 100644 --- a/io/zenoh-transport/src/common/pipeline.rs +++ b/io/zenoh-transport/src/common/pipeline.rs @@ -17,7 +17,7 @@ use zenoh_codec::{transport::batch::BatchError, WCodec, Zenoh080}; use zenoh_config::QueueSizeConf; use zenoh_core::zlock; use zenoh_protocol::{ - core::{Priority, Reliability}, + core::Priority, network::NetworkMessage, transport::{ fragment::FragmentHeader, @@ -210,7 +210,7 @@ impl StageIn { // The Frame let frame = FrameHeader { - reliability: Reliability::Reliable, // TODO + reliability: msg.reliability, sn, ext_qos: frame::ext::QoSType::new(priority), }; From ff8699bddbec1f059ecfb1602b6419d798c18cdb Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Fri, 9 Aug 2024 15:07:39 +0200 Subject: [PATCH 03/33] Change primitives --- zenoh/src/api/publisher.rs | 71 +++++---- zenoh/src/api/session.rs | 6 +- zenoh/src/net/primitives/demux.rs | 2 +- zenoh/src/net/primitives/mod.rs | 13 +- zenoh/src/net/primitives/mux.rs | 16 +- zenoh/src/net/routing/dispatcher/face.rs | 14 +- zenoh/src/net/routing/dispatcher/pubsub.rs | 97 +++++++----- zenoh/src/net/runtime/adminspace.rs | 8 +- zenoh/src/net/tests/tables.rs | 171 +++++++++++---------- 9 files changed, 211 insertions(+), 187 deletions(-) diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index f4b969b18f..d8e3ecca61 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -23,7 +23,7 @@ use std::{ use futures::Sink; use zenoh_core::{zread, Resolvable, Resolve, Wait}; use zenoh_protocol::{ - core::CongestionControl, + core::{CongestionControl, Reliability}, network::{push::ext, Push}, zenoh::{Del, PushBody, Put}, }; @@ -582,40 +582,43 @@ impl Publisher<'_> { timestamp }; if self.destination != Locality::SessionLocal { - primitives.send_push(Push { - wire_expr: self.key_expr.to_wire(&self.session).to_owned(), - ext_qos: ext::QoSType::new( - self.priority.into(), - self.congestion_control, - self.is_express, - ), - ext_tstamp: None, - ext_nodeid: ext::NodeIdType::DEFAULT, - payload: match kind { - SampleKind::Put => PushBody::Put(Put { - timestamp, - encoding: encoding.clone().into(), - #[cfg(feature = "unstable")] - ext_sinfo: source_info.into(), - #[cfg(not(feature = "unstable"))] - ext_sinfo: None, - #[cfg(feature = "shared-memory")] - ext_shm: None, - ext_attachment: attachment.clone().map(|a| a.into()), - ext_unknown: vec![], - payload: payload.clone().into(), - }), - SampleKind::Delete => PushBody::Del(Del { - timestamp, - #[cfg(feature = "unstable")] - ext_sinfo: source_info.into(), - #[cfg(not(feature = "unstable"))] - ext_sinfo: None, - ext_attachment: attachment.clone().map(|a| a.into()), - ext_unknown: vec![], - }), + primitives.send_push( + Push { + wire_expr: self.key_expr.to_wire(&self.session).to_owned(), + ext_qos: ext::QoSType::new( + self.priority.into(), + self.congestion_control, + self.is_express, + ), + ext_tstamp: None, + ext_nodeid: ext::NodeIdType::DEFAULT, + payload: match kind { + SampleKind::Put => PushBody::Put(Put { + timestamp, + encoding: encoding.clone().into(), + #[cfg(feature = "unstable")] + ext_sinfo: source_info.into(), + #[cfg(not(feature = "unstable"))] + ext_sinfo: None, + #[cfg(feature = "shared-memory")] + ext_shm: None, + ext_attachment: attachment.clone().map(|a| a.into()), + ext_unknown: vec![], + payload: payload.clone().into(), + }), + SampleKind::Delete => PushBody::Del(Del { + timestamp, + #[cfg(feature = "unstable")] + ext_sinfo: source_info.into(), + #[cfg(not(feature = "unstable"))] + ext_sinfo: None, + ext_attachment: attachment.clone().map(|a| a.into()), + ext_unknown: vec![], + }), + }, }, - }); + Reliability::Reliable, // TODO + ); } if self.destination != Locality::Remote { let data_info = DataInfo { diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index ed1c75d3f2..c1ba753f68 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -2333,7 +2333,7 @@ impl Primitives for Session { } } - fn send_push(&self, msg: Push) { + fn send_push(&self, msg: Push, _reliability: Reliability) { trace!("recv Push {:?}", msg); match msg.payload { PushBody::Put(m) => { @@ -2791,8 +2791,8 @@ impl crate::net::primitives::EPrimitives for Session { } #[inline] - fn send_push(&self, msg: Push) { - (self as &dyn Primitives).send_push(msg) + fn send_push(&self, msg: Push, reliability: Reliability) { + (self as &dyn Primitives).send_push(msg, reliability) } #[inline] diff --git a/zenoh/src/net/primitives/demux.rs b/zenoh/src/net/primitives/demux.rs index 59111e5441..e4774aab4a 100644 --- a/zenoh/src/net/primitives/demux.rs +++ b/zenoh/src/net/primitives/demux.rs @@ -66,7 +66,7 @@ impl TransportPeerEventHandler for DeMux { } match msg.body { - NetworkBody::Push(m) => self.face.send_push(m), + NetworkBody::Push(m) => self.face.send_push(m, msg.reliability), NetworkBody::Declare(m) => self.face.send_declare(m), NetworkBody::Interest(m) => self.face.send_interest(m), NetworkBody::Request(m) => self.face.send_request(m), diff --git a/zenoh/src/net/primitives/mod.rs b/zenoh/src/net/primitives/mod.rs index 837571f7f6..21526466f5 100644 --- a/zenoh/src/net/primitives/mod.rs +++ b/zenoh/src/net/primitives/mod.rs @@ -18,8 +18,9 @@ use std::any::Any; pub use demux::*; pub use mux::*; -use zenoh_protocol::network::{ - interest::Interest, Declare, Push, Request, Response, ResponseFinal, +use zenoh_protocol::{ + core::Reliability, + network::{interest::Interest, Declare, Push, Request, Response, ResponseFinal}, }; use super::routing::RoutingContext; @@ -29,7 +30,7 @@ pub trait Primitives: Send + Sync { fn send_declare(&self, msg: Declare); - fn send_push(&self, msg: Push); + fn send_push(&self, msg: Push, reliability: Reliability); fn send_request(&self, msg: Request); @@ -47,7 +48,7 @@ pub(crate) trait EPrimitives: Send + Sync { fn send_declare(&self, ctx: RoutingContext); - fn send_push(&self, msg: Push); + fn send_push(&self, msg: Push, reliability: Reliability); fn send_request(&self, msg: Request); @@ -64,7 +65,7 @@ impl Primitives for DummyPrimitives { fn send_declare(&self, _msg: Declare) {} - fn send_push(&self, _msg: Push) {} + fn send_push(&self, _msg: Push, _reliability: Reliability) {} fn send_request(&self, _msg: Request) {} @@ -80,7 +81,7 @@ impl EPrimitives for DummyPrimitives { fn send_declare(&self, _ctx: RoutingContext) {} - fn send_push(&self, _msg: Push) {} + fn send_push(&self, _msg: Push, _reliability: Reliability) {} fn send_request(&self, _msg: Request) {} diff --git a/zenoh/src/net/primitives/mux.rs b/zenoh/src/net/primitives/mux.rs index b017e3858a..47067f231e 100644 --- a/zenoh/src/net/primitives/mux.rs +++ b/zenoh/src/net/primitives/mux.rs @@ -100,10 +100,10 @@ impl Primitives for Mux { } } - fn send_push(&self, msg: Push) { + fn send_push(&self, msg: Push, reliability: Reliability) { let msg = NetworkMessage { body: NetworkBody::Push(msg), - reliability: Reliability::Reliable, + reliability, #[cfg(feature = "stats")] size: None, }; @@ -258,10 +258,10 @@ impl EPrimitives for Mux { } } - fn send_push(&self, msg: Push) { + fn send_push(&self, msg: Push, reliability: Reliability) { let msg = NetworkMessage { body: NetworkBody::Push(msg), - reliability: Reliability::Reliable, + reliability, #[cfg(feature = "stats")] size: None, }; @@ -430,10 +430,10 @@ impl Primitives for McastMux { } } - fn send_push(&self, msg: Push) { + fn send_push(&self, msg: Push, reliability: Reliability) { let msg = NetworkMessage { body: NetworkBody::Push(msg), - reliability: Reliability::Reliable, + reliability, #[cfg(feature = "stats")] size: None, }; @@ -588,10 +588,10 @@ impl EPrimitives for McastMux { } } - fn send_push(&self, msg: Push) { + fn send_push(&self, msg: Push, reliability: Reliability) { let msg = NetworkMessage { body: NetworkBody::Push(msg), - reliability: Reliability::Reliable, + reliability, #[cfg(feature = "stats")] size: None, }; diff --git a/zenoh/src/net/routing/dispatcher/face.rs b/zenoh/src/net/routing/dispatcher/face.rs index bbc910b124..0bc14450a7 100644 --- a/zenoh/src/net/routing/dispatcher/face.rs +++ b/zenoh/src/net/routing/dispatcher/face.rs @@ -20,7 +20,7 @@ use std::{ use tokio_util::sync::CancellationToken; use zenoh_protocol::{ - core::{ExprId, WhatAmI, ZenohIdProto}, + core::{ExprId, Reliability, WhatAmI, ZenohIdProto}, network::{ interest::{InterestId, InterestMode, InterestOptions}, Mapping, Push, Request, RequestId, Response, ResponseFinal, @@ -379,16 +379,8 @@ impl Primitives for Face { } #[inline] - fn send_push(&self, msg: Push) { - full_reentrant_route_data( - &self.tables, - &self.state, - &msg.wire_expr, - msg.ext_qos, - msg.ext_tstamp, - msg.payload, - msg.ext_nodeid.node_id, - ); + fn send_push(&self, msg: Push, reliability: Reliability) { + route_data(&self.tables, &self.state, msg, reliability); } fn send_request(&self, msg: Request) { diff --git a/zenoh/src/net/routing/dispatcher/pubsub.rs b/zenoh/src/net/routing/dispatcher/pubsub.rs index 84c8433a48..7334f4f267 100644 --- a/zenoh/src/net/routing/dispatcher/pubsub.rs +++ b/zenoh/src/net/routing/dispatcher/pubsub.rs @@ -15,7 +15,7 @@ use std::{collections::HashMap, sync::Arc}; use zenoh_core::zread; use zenoh_protocol::{ - core::{key_expr::keyexpr, WhatAmI, WireExpr}, + core::{key_expr::keyexpr, Reliability, WhatAmI, WireExpr}, network::{ declare::{ext, subscriber::ext::SubscriberInfo, SubscriberId}, Push, @@ -385,42 +385,42 @@ macro_rules! inc_stats { }; } -pub fn full_reentrant_route_data( +pub fn route_data( tables_ref: &Arc, face: &FaceState, - expr: &WireExpr, - ext_qos: ext::QoSType, - ext_tstamp: Option, - mut payload: PushBody, - routing_context: NodeId, + mut msg: Push, + reliability: Reliability, ) { let tables = zread!(tables_ref.tables); - match tables.get_mapping(face, &expr.scope, expr.mapping).cloned() { + match tables + .get_mapping(face, &msg.wire_expr.scope, msg.wire_expr.mapping) + .cloned() + { Some(prefix) => { tracing::trace!( "{} Route data for res {}{}", face, prefix.expr(), - expr.suffix.as_ref() + msg.wire_expr.suffix.as_ref() ); - let mut expr = RoutingExpr::new(&prefix, expr.suffix.as_ref()); + let mut expr = RoutingExpr::new(&prefix, msg.wire_expr.suffix.as_ref()); #[cfg(feature = "stats")] let admin = expr.full_expr().starts_with("@/"); #[cfg(feature = "stats")] if !admin { - inc_stats!(face, rx, user, payload) + inc_stats!(face, rx, user, msg.payload) } else { - inc_stats!(face, rx, admin, payload) + inc_stats!(face, rx, admin, msg.payload) } if tables.hat_code.ingress_filter(&tables, face, &mut expr) { let res = Resource::get_resource(&prefix, expr.suffix); - let route = get_data_route(&tables, face, &res, &mut expr, routing_context); + let route = get_data_route(&tables, face, &res, &mut expr, msg.ext_nodeid.node_id); if !route.is_empty() { - treat_timestamp!(&tables.hlc, payload, tables.drop_future_timestamp); + treat_timestamp!(&tables.hlc, msg.payload, tables.drop_future_timestamp); if route.len() == 1 { let (outface, key_expr, context) = route.values().next().unwrap(); @@ -431,18 +431,21 @@ pub fn full_reentrant_route_data( drop(tables); #[cfg(feature = "stats")] if !admin { - inc_stats!(face, tx, user, payload) + inc_stats!(face, tx, user, msg.payload) } else { - inc_stats!(face, tx, admin, payload) + inc_stats!(face, tx, admin, msg.payload) } - outface.primitives.send_push(Push { - wire_expr: key_expr.into(), - ext_qos, - ext_tstamp, - ext_nodeid: ext::NodeIdType { node_id: *context }, - payload, - }) + outface.primitives.send_push( + Push { + wire_expr: key_expr.into(), + ext_qos: msg.ext_qos, + ext_tstamp: msg.ext_tstamp, + ext_nodeid: ext::NodeIdType { node_id: *context }, + payload: msg.payload, + }, + reliability, + ) } } else if tables.whatami == WhatAmI::Router { let route = route @@ -459,18 +462,21 @@ pub fn full_reentrant_route_data( for (outface, key_expr, context) in route { #[cfg(feature = "stats")] if !admin { - inc_stats!(face, tx, user, payload) + inc_stats!(face, tx, user, msg.payload) } else { - inc_stats!(face, tx, admin, payload) + inc_stats!(face, tx, admin, msg.payload) } - outface.primitives.send_push(Push { - wire_expr: key_expr, - ext_qos, - ext_tstamp: None, - ext_nodeid: ext::NodeIdType { node_id: context }, - payload: payload.clone(), - }) + outface.primitives.send_push( + Push { + wire_expr: key_expr, + ext_qos: msg.ext_qos, + ext_tstamp: None, + ext_nodeid: ext::NodeIdType { node_id: context }, + payload: msg.payload.clone(), + }, + reliability, + ) } } else { drop(tables); @@ -483,18 +489,21 @@ pub fn full_reentrant_route_data( { #[cfg(feature = "stats")] if !admin { - inc_stats!(face, tx, user, payload) + inc_stats!(face, tx, user, msg.payload) } else { - inc_stats!(face, tx, admin, payload) + inc_stats!(face, tx, admin, msg.payload) } - outface.primitives.send_push(Push { - wire_expr: key_expr.into(), - ext_qos, - ext_tstamp: None, - ext_nodeid: ext::NodeIdType { node_id: *context }, - payload: payload.clone(), - }) + outface.primitives.send_push( + Push { + wire_expr: key_expr.into(), + ext_qos: msg.ext_qos, + ext_tstamp: None, + ext_nodeid: ext::NodeIdType { node_id: *context }, + payload: msg.payload.clone(), + }, + reliability, + ) } } } @@ -502,7 +511,11 @@ pub fn full_reentrant_route_data( } } None => { - tracing::error!("{} Route data with unknown scope {}!", face, expr.scope); + tracing::error!( + "{} Route data with unknown scope {}!", + face, + msg.wire_expr.scope + ); } } } diff --git a/zenoh/src/net/runtime/adminspace.rs b/zenoh/src/net/runtime/adminspace.rs index ce87d68ef0..d3e2a3c1ad 100644 --- a/zenoh/src/net/runtime/adminspace.rs +++ b/zenoh/src/net/runtime/adminspace.rs @@ -26,7 +26,7 @@ use zenoh_plugin_trait::{PluginControl, PluginStatus}; #[cfg(feature = "plugins")] use zenoh_protocol::core::key_expr::keyexpr; use zenoh_protocol::{ - core::{key_expr::OwnedKeyExpr, ExprId, WireExpr, EMPTY_EXPR_ID}, + core::{key_expr::OwnedKeyExpr, ExprId, Reliability, WireExpr, EMPTY_EXPR_ID}, network::{ declare::{ queryable::ext::QueryableInfoType, subscriber::ext::SubscriberInfo, QueryableId, @@ -375,7 +375,7 @@ impl Primitives for AdminSpace { } } - fn send_push(&self, msg: Push) { + fn send_push(&self, msg: Push, _reliability: Reliability) { trace!("recv Push {:?}", msg); { let conf = self.context.runtime.state.config.lock(); @@ -516,8 +516,8 @@ impl crate::net::primitives::EPrimitives for AdminSpace { } #[inline] - fn send_push(&self, msg: Push) { - (self as &dyn Primitives).send_push(msg) + fn send_push(&self, msg: Push, reliability: Reliability) { + (self as &dyn Primitives).send_push(msg, reliability) } #[inline] diff --git a/zenoh/src/net/tests/tables.rs b/zenoh/src/net/tests/tables.rs index 5fd8a49261..bab638af83 100644 --- a/zenoh/src/net/tests/tables.rs +++ b/zenoh/src/net/tests/tables.rs @@ -26,7 +26,7 @@ use zenoh_protocol::{ EMPTY_EXPR_ID, }, network::{ - declare::subscriber::ext::SubscriberInfo, ext, Declare, DeclareBody, DeclareKeyExpr, + declare::subscriber::ext::SubscriberInfo, ext, Declare, DeclareBody, DeclareKeyExpr, Push, }, zenoh::{PushBody, Put}, }; @@ -534,7 +534,7 @@ impl Primitives for ClientPrimitives { } } - fn send_push(&self, msg: zenoh_protocol::network::Push) { + fn send_push(&self, msg: zenoh_protocol::network::Push, _reliability: Reliability) { *zlock!(self.data) = Some(msg.wire_expr.to_owned()); } @@ -563,7 +563,7 @@ impl EPrimitives for ClientPrimitives { } } - fn send_push(&self, msg: zenoh_protocol::network::Push) { + fn send_push(&self, msg: zenoh_protocol::network::Push, _reliability: Reliability) { *zlock!(self.data) = Some(msg.wire_expr.to_owned()); } @@ -736,23 +736,26 @@ fn client_test() { primitives1.clear_data(); primitives2.clear_data(); - full_reentrant_route_data( + route_data( &tables, &face0.upgrade().unwrap(), - &"test/client/z1_wr1".into(), - ext::QoSType::DEFAULT, - None, - PushBody::Put(Put { - timestamp: None, - encoding: Encoding::empty(), - ext_sinfo: None, - #[cfg(feature = "shared-memory")] - ext_shm: None, - ext_unknown: vec![], - payload: ZBuf::empty(), - ext_attachment: None, - }), - 0, + Push { + wire_expr: "test/client/z1_wr1".into(), + ext_qos: ext::QoSType::DEFAULT, + ext_tstamp: None, + ext_nodeid: ext::NodeIdType { node_id: 0 }, + payload: PushBody::Put(Put { + timestamp: None, + encoding: Encoding::empty(), + ext_sinfo: None, + #[cfg(feature = "shared-memory")] + ext_shm: None, + ext_unknown: vec![], + payload: ZBuf::empty(), + ext_attachment: None, + }), + }, + Reliability::Reliable, ); // functional check @@ -770,23 +773,26 @@ fn client_test() { primitives0.clear_data(); primitives1.clear_data(); primitives2.clear_data(); - full_reentrant_route_data( + route_data( &router.tables, &face0.upgrade().unwrap(), - &WireExpr::from(11).with_suffix("/z1_wr2"), - ext::QoSType::DEFAULT, - None, - PushBody::Put(Put { - timestamp: None, - encoding: Encoding::empty(), - ext_sinfo: None, - #[cfg(feature = "shared-memory")] - ext_shm: None, - ext_unknown: vec![], - payload: ZBuf::empty(), - ext_attachment: None, - }), - 0, + Push { + wire_expr: WireExpr::from(11).with_suffix("/z1_wr2"), + ext_qos: ext::QoSType::DEFAULT, + ext_tstamp: None, + ext_nodeid: ext::NodeIdType { node_id: 0 }, + payload: PushBody::Put(Put { + timestamp: None, + encoding: Encoding::empty(), + ext_sinfo: None, + #[cfg(feature = "shared-memory")] + ext_shm: None, + ext_unknown: vec![], + payload: ZBuf::empty(), + ext_attachment: None, + }), + }, + Reliability::Reliable, ); // functional check @@ -804,23 +810,26 @@ fn client_test() { primitives0.clear_data(); primitives1.clear_data(); primitives2.clear_data(); - full_reentrant_route_data( + route_data( &router.tables, &face1.upgrade().unwrap(), - &"test/client/**".into(), - ext::QoSType::DEFAULT, - None, - PushBody::Put(Put { - timestamp: None, - encoding: Encoding::empty(), - ext_sinfo: None, - #[cfg(feature = "shared-memory")] - ext_shm: None, - ext_unknown: vec![], - payload: ZBuf::empty(), - ext_attachment: None, - }), - 0, + Push { + wire_expr: "test/client/**".into(), + ext_qos: ext::QoSType::DEFAULT, + ext_tstamp: None, + ext_nodeid: ext::NodeIdType { node_id: 0 }, + payload: PushBody::Put(Put { + timestamp: None, + encoding: Encoding::empty(), + ext_sinfo: None, + #[cfg(feature = "shared-memory")] + ext_shm: None, + ext_unknown: vec![], + payload: ZBuf::empty(), + ext_attachment: None, + }), + }, + Reliability::Reliable, ); // functional check @@ -838,23 +847,26 @@ fn client_test() { primitives0.clear_data(); primitives1.clear_data(); primitives2.clear_data(); - full_reentrant_route_data( + route_data( &router.tables, &face0.upgrade().unwrap(), - &12.into(), - ext::QoSType::DEFAULT, - None, - PushBody::Put(Put { - timestamp: None, - encoding: Encoding::empty(), - ext_sinfo: None, - #[cfg(feature = "shared-memory")] - ext_shm: None, - ext_unknown: vec![], - payload: ZBuf::empty(), - ext_attachment: None, - }), - 0, + Push { + wire_expr: 12.into(), + ext_qos: ext::QoSType::DEFAULT, + ext_tstamp: None, + ext_nodeid: ext::NodeIdType { node_id: 0 }, + payload: PushBody::Put(Put { + timestamp: None, + encoding: Encoding::empty(), + ext_sinfo: None, + #[cfg(feature = "shared-memory")] + ext_shm: None, + ext_unknown: vec![], + payload: ZBuf::empty(), + ext_attachment: None, + }), + }, + Reliability::Reliable, ); // functional check @@ -872,23 +884,26 @@ fn client_test() { primitives0.clear_data(); primitives1.clear_data(); primitives2.clear_data(); - full_reentrant_route_data( + route_data( &router.tables, &face1.upgrade().unwrap(), - &22.into(), - ext::QoSType::DEFAULT, - None, - PushBody::Put(Put { - timestamp: None, - encoding: Encoding::empty(), - ext_sinfo: None, - #[cfg(feature = "shared-memory")] - ext_shm: None, - ext_unknown: vec![], - payload: ZBuf::empty(), - ext_attachment: None, - }), - 0, + Push { + wire_expr: 22.into(), + ext_qos: ext::QoSType::DEFAULT, + ext_tstamp: None, + ext_nodeid: ext::NodeIdType { node_id: 0 }, + payload: PushBody::Put(Put { + timestamp: None, + encoding: Encoding::empty(), + ext_sinfo: None, + #[cfg(feature = "shared-memory")] + ext_shm: None, + ext_unknown: vec![], + payload: ZBuf::empty(), + ext_attachment: None, + }), + }, + Reliability::Reliable, ); // functional check From ce6cdec678ebbeccac196546cdad0a123c85822a Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Fri, 9 Aug 2024 18:33:17 +0200 Subject: [PATCH 04/33] Api publisher reliability --- zenoh/src/api/admin.rs | 10 +++++++ zenoh/src/api/builders/publisher.rs | 29 +++++++++++++++++++ zenoh/src/api/builders/sample.rs | 17 +++++++++++ zenoh/src/api/publisher.rs | 10 ++++++- zenoh/src/api/sample.rs | 29 ++++++++++++++++++- zenoh/src/api/session.rs | 44 +++++++++++++++++++++++++---- 6 files changed, 132 insertions(+), 7 deletions(-) diff --git a/zenoh/src/api/admin.rs b/zenoh/src/api/admin.rs index e794c87db5..8c20a275c1 100644 --- a/zenoh/src/api/admin.rs +++ b/zenoh/src/api/admin.rs @@ -19,6 +19,8 @@ use std::{ use zenoh_core::{Result as ZResult, Wait}; use zenoh_keyexpr::keyexpr; +#[cfg(feature = "unstable")] +use zenoh_protocol::core::Reliability; use zenoh_protocol::{core::WireExpr, network::NetworkMessage}; use zenoh_transport::{ TransportEventHandler, TransportMulticastEventHandler, TransportPeer, TransportPeerEventHandler, @@ -171,6 +173,8 @@ impl TransportMulticastEventHandler for Handler { Some(info), serde_json::to_vec(&peer).unwrap().into(), SubscriberKind::Subscriber, + #[cfg(feature = "unstable")] + Reliability::Reliable, None, ); Ok(Arc::new(PeerHandler { @@ -220,6 +224,8 @@ impl TransportPeerEventHandler for PeerHandler { Some(info), serde_json::to_vec(&link).unwrap().into(), SubscriberKind::Subscriber, + #[cfg(feature = "unstable")] + Reliability::Reliable, None, ); } @@ -240,6 +246,8 @@ impl TransportPeerEventHandler for PeerHandler { Some(info), vec![0u8; 0].into(), SubscriberKind::Subscriber, + #[cfg(feature = "unstable")] + Reliability::Reliable, None, ); } @@ -257,6 +265,8 @@ impl TransportPeerEventHandler for PeerHandler { Some(info), vec![0u8; 0].into(), SubscriberKind::Subscriber, + #[cfg(feature = "unstable")] + Reliability::Reliable, None, ); } diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index 666b4378e0..0404838a04 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -14,6 +14,8 @@ use std::future::{IntoFuture, Ready}; use zenoh_core::{Resolvable, Result as ZResult, Wait}; +#[cfg(feature = "unstable")] +use zenoh_protocol::core::Reliability; use zenoh_protocol::{core::CongestionControl, network::Mapping}; #[cfg(feature = "unstable")] @@ -111,6 +113,15 @@ impl PublicationBuilder, T> { self.publisher = self.publisher.allowed_destination(destination); self } + /// Change the `reliability` to apply when routing the data. + #[zenoh_macros::unstable] + #[inline] + pub fn reliability(self, reliability: Reliability) -> Self { + Self { + publisher: self.publisher.reliability(reliability), + ..self + } + } } impl EncodingBuilderTrait for PublisherBuilder<'_, '_> { @@ -239,6 +250,8 @@ pub struct PublisherBuilder<'a, 'b: 'a> { pub(crate) congestion_control: CongestionControl, pub(crate) priority: Priority, pub(crate) is_express: bool, + #[cfg(feature = "unstable")] + pub(crate) reliability: Reliability, pub(crate) destination: Locality, } @@ -254,6 +267,8 @@ impl<'a, 'b> Clone for PublisherBuilder<'a, 'b> { congestion_control: self.congestion_control, priority: self.priority, is_express: self.is_express, + #[cfg(feature = "unstable")] + reliability: self.reliability, destination: self.destination, } } @@ -294,6 +309,16 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { self } + /// Change the `reliability`` to apply when routing the data. + #[zenoh_macros::unstable] + #[inline] + pub fn reliability(self, reliability: Reliability) -> Self { + Self { + reliability, + ..self + } + } + // internal function for performing the publication fn create_one_shot_publisher(self) -> ZResult> { Ok(Publisher { @@ -306,6 +331,8 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { is_express: self.is_express, destination: self.destination, #[cfg(feature = "unstable")] + reliability: self.reliability, + #[cfg(feature = "unstable")] matching_listeners: Default::default(), undeclare_on_drop: true, }) @@ -361,6 +388,8 @@ impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { is_express: self.is_express, destination: self.destination, #[cfg(feature = "unstable")] + reliability: self.reliability, + #[cfg(feature = "unstable")] matching_listeners: Default::default(), undeclare_on_drop: true, }) diff --git a/zenoh/src/api/builders/sample.rs b/zenoh/src/api/builders/sample.rs index 53cf099448..4c1fa81406 100644 --- a/zenoh/src/api/builders/sample.rs +++ b/zenoh/src/api/builders/sample.rs @@ -16,6 +16,8 @@ use std::marker::PhantomData; use uhlc::Timestamp; use zenoh_core::zresult; use zenoh_protocol::core::CongestionControl; +#[cfg(feature = "unstable")] +use zenoh_protocol::core::Reliability; use crate::api::{ bytes::{OptionZBytes, ZBytes}, @@ -87,6 +89,8 @@ impl SampleBuilder { timestamp: None, qos: QoS::default(), #[cfg(feature = "unstable")] + reliability: Reliability::DEFAULT, + #[cfg(feature = "unstable")] source_info: SourceInfo::empty(), attachment: None, }, @@ -117,6 +121,8 @@ impl SampleBuilder { timestamp: None, qos: QoS::default(), #[cfg(feature = "unstable")] + reliability: Reliability::DEFAULT, + #[cfg(feature = "unstable")] source_info: SourceInfo::empty(), attachment: None, }, @@ -147,6 +153,17 @@ impl SampleBuilder { _t: PhantomData::, } } + + #[zenoh_macros::unstable] + pub fn reliability(self, reliability: Reliability) -> Self { + Self { + sample: Sample { + reliability, + ..self.sample + }, + _t: PhantomData::, + } + } } impl TimestampBuilderTrait for SampleBuilder { diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index d8e3ecca61..4cab752f79 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -145,6 +145,8 @@ pub struct Publisher<'a> { pub(crate) is_express: bool, pub(crate) destination: Locality, #[cfg(feature = "unstable")] + pub(crate) reliability: Reliability, + #[cfg(feature = "unstable")] pub(crate) matching_listeners: Arc>>, pub(crate) undeclare_on_drop: bool, } @@ -561,6 +563,7 @@ impl<'a> Sink for Publisher<'a> { } impl Publisher<'_> { + #[allow(clippy::too_many_arguments)] // TODO fixme pub(crate) fn resolve_put( &self, payload: ZBytes, @@ -617,7 +620,10 @@ impl Publisher<'_> { }), }, }, - Reliability::Reliable, // TODO + #[cfg(feature = "unstable")] + self.reliability, + #[cfg(not(feature = "unstable"))] + Reliability::DEFAULT, ); } if self.destination != Locality::Remote { @@ -640,6 +646,8 @@ impl Publisher<'_> { Some(data_info), payload.into(), SubscriberKind::Subscriber, + #[cfg(feature = "unstable")] + self.reliability, attachment, ); } diff --git a/zenoh/src/api/sample.rs b/zenoh/src/api/sample.rs index 220785c668..253e98d4b5 100644 --- a/zenoh/src/api/sample.rs +++ b/zenoh/src/api/sample.rs @@ -18,6 +18,8 @@ use std::{convert::TryFrom, fmt}; #[cfg(feature = "unstable")] use serde::Serialize; use zenoh_config::wrappers::EntityGlobalId; +#[cfg(feature = "unstable")] +use zenoh_protocol::core::Reliability; use zenoh_protocol::{ core::{CongestionControl, Timestamp}, network::declare::ext::QoSType, @@ -63,6 +65,7 @@ pub(crate) trait DataInfoIntoSample { self, key_expr: IntoKeyExpr, payload: IntoZBytes, + #[cfg(feature = "unstable")] reliability: Reliability, attachment: Option, ) -> Sample where @@ -80,6 +83,7 @@ impl DataInfoIntoSample for DataInfo { self, key_expr: IntoKeyExpr, payload: IntoZBytes, + #[cfg(feature = "unstable")] reliability: Reliability, attachment: Option, ) -> Sample where @@ -94,6 +98,8 @@ impl DataInfoIntoSample for DataInfo { timestamp: self.timestamp, qos: self.qos, #[cfg(feature = "unstable")] + reliability, + #[cfg(feature = "unstable")] source_info: SourceInfo { source_id: self.source_id, source_sn: self.source_sn, @@ -109,6 +115,7 @@ impl DataInfoIntoSample for Option { self, key_expr: IntoKeyExpr, payload: IntoZBytes, + #[cfg(feature = "unstable")] reliability: Reliability, attachment: Option, ) -> Sample where @@ -116,7 +123,13 @@ impl DataInfoIntoSample for Option { IntoZBytes: Into, { if let Some(data_info) = self { - data_info.into_sample(key_expr, payload, attachment) + data_info.into_sample( + key_expr, + payload, + #[cfg(feature = "unstable")] + reliability, + attachment, + ) } else { Sample { key_expr: key_expr.into(), @@ -126,6 +139,8 @@ impl DataInfoIntoSample for Option { timestamp: None, qos: QoS::default(), #[cfg(feature = "unstable")] + reliability, + #[cfg(feature = "unstable")] source_info: SourceInfo::empty(), attachment, } @@ -252,6 +267,8 @@ pub struct SampleFields { pub priority: Priority, pub congestion_control: CongestionControl, #[cfg(feature = "unstable")] + pub reliability: Reliability, + #[cfg(feature = "unstable")] pub source_info: SourceInfo, pub attachment: Option, } @@ -268,6 +285,8 @@ impl From for SampleFields { priority: sample.qos.priority(), congestion_control: sample.qos.congestion_control(), #[cfg(feature = "unstable")] + reliability: sample.reliability, + #[cfg(feature = "unstable")] source_info: sample.source_info, attachment: sample.attachment, } @@ -285,6 +304,8 @@ pub struct Sample { pub(crate) timestamp: Option, pub(crate) qos: QoS, #[cfg(feature = "unstable")] + pub(crate) reliability: Reliability, + #[cfg(feature = "unstable")] pub(crate) source_info: SourceInfo, pub(crate) attachment: Option, } @@ -336,6 +357,12 @@ impl Sample { self.qos.priority() } + /// Gets the reliability of this Sample + #[zenoh_macros::unstable] + pub fn reliability(&self) -> Reliability { + self.reliability + } + /// Gets the express flag value. If `true`, the message is not batched during transmission, in order to reduce latency. pub fn express(&self) -> bool { self.qos.express() diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index c1ba753f68..b0c7543be8 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -413,6 +413,8 @@ impl<'s, 'a> SessionDeclarations<'s, 'a> for SessionRef<'a> { congestion_control: CongestionControl::DEFAULT, priority: Priority::DEFAULT, is_express: false, + #[cfg(feature = "unstable")] + reliability: Reliability::DEFAULT, destination: Locality::default(), } } @@ -1653,6 +1655,7 @@ impl Session { } } + #[allow(clippy::too_many_arguments)] // TODO fixme pub(crate) fn execute_subscriber_callbacks( &self, local: bool, @@ -1660,6 +1663,7 @@ impl Session { info: Option, payload: ZBuf, kind: SubscriberKind, + #[cfg(feature = "unstable")] reliability: Reliability, attachment: Option, ) { let mut callbacks = SingleOrVec::default(); @@ -1708,13 +1712,23 @@ impl Session { drop(state); let zenoh_collections::single_or_vec::IntoIter { drain, last } = callbacks.into_iter(); for (cb, key_expr) in drain { - let sample = info - .clone() - .into_sample(key_expr, payload.clone(), attachment.clone()); + let sample = info.clone().into_sample( + key_expr, + payload.clone(), + #[cfg(feature = "unstable")] + reliability, + attachment.clone(), + ); cb(sample); } if let Some((cb, key_expr)) = last { - let sample = info.into_sample(key_expr, payload, attachment.clone()); + let sample = info.into_sample( + key_expr, + payload, + #[cfg(feature = "unstable")] + reliability, + attachment.clone(), + ); cb(sample); } } @@ -2103,6 +2117,8 @@ impl<'s> SessionDeclarations<'s, 'static> for Arc { congestion_control: CongestionControl::DEFAULT, priority: Priority::DEFAULT, is_express: false, + #[cfg(feature = "unstable")] + reliability: Reliability::DEFAULT, destination: Locality::default(), } } @@ -2234,6 +2250,8 @@ impl Primitives for Session { timestamp: None, qos: QoS::default(), #[cfg(feature = "unstable")] + reliability: Reliability::Reliable, + #[cfg(feature = "unstable")] source_info: SourceInfo::empty(), #[cfg(feature = "unstable")] attachment: None, @@ -2256,6 +2274,8 @@ impl Primitives for Session { ZBuf::default(), SubscriberKind::LivelinessSubscriber, #[cfg(feature = "unstable")] + Reliability::Reliable, + #[cfg(feature = "unstable")] None, ); } @@ -2286,6 +2306,8 @@ impl Primitives for Session { ZBuf::default(), SubscriberKind::LivelinessSubscriber, #[cfg(feature = "unstable")] + Reliability::Reliable, + #[cfg(feature = "unstable")] None, ); } else if m.ext_wire_expr.wire_expr != WireExpr::empty() { @@ -2308,6 +2330,8 @@ impl Primitives for Session { ZBuf::default(), SubscriberKind::LivelinessSubscriber, #[cfg(feature = "unstable")] + Reliability::Reliable, + #[cfg(feature = "unstable")] None, ); } @@ -2351,6 +2375,8 @@ impl Primitives for Session { Some(info), m.payload, SubscriberKind::Subscriber, + #[cfg(feature = "unstable")] + _reliability, m.ext_attachment.map(Into::into), ) } @@ -2369,6 +2395,8 @@ impl Primitives for Session { Some(info), ZBuf::empty(), SubscriberKind::Subscriber, + #[cfg(feature = "unstable")] + _reliability, m.ext_attachment.map(Into::into), ) } @@ -2486,7 +2514,13 @@ impl Primitives for Session { attachment: _attachment.map(Into::into), }, }; - let sample = info.into_sample(key_expr.into_owned(), payload, attachment); + let sample = info.into_sample( + key_expr.into_owned(), + payload, + #[cfg(feature = "unstable")] + Reliability::Reliable, + attachment, + ); let new_reply = Reply { result: Ok(sample), #[cfg(feature = "unstable")] From 3ac6c3f3780ac239a5a5562e42aa6ccb4fe815c5 Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Fri, 9 Aug 2024 18:46:10 +0200 Subject: [PATCH 05/33] Fix serialization_batch test --- io/zenoh-transport/src/common/batch.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/io/zenoh-transport/src/common/batch.rs b/io/zenoh-transport/src/common/batch.rs index 5537ec46fb..715d487b8c 100644 --- a/io/zenoh-transport/src/common/batch.rs +++ b/io/zenoh-transport/src/common/batch.rs @@ -570,7 +570,7 @@ mod tests { let mut batch = WBatch::new(config); let tmsg: TransportMessage = KeepAlive.into(); - let nmsg: NetworkMessage = Push { + let mut nmsg: NetworkMessage = Push { wire_expr: WireExpr::empty(), ext_qos: ext::QoSType::new(Priority::DEFAULT, CongestionControl::Block, false), ext_tstamp: None, @@ -601,6 +601,7 @@ mod tests { sn: 0, ext_qos: frame::ext::QoSType::DEFAULT, }; + nmsg.reliability = Reliability::Reliable; // Serialize with a frame batch.encode((&nmsg, &frame)).unwrap(); @@ -608,6 +609,7 @@ mod tests { nmsgs_in.push(nmsg.clone()); frame.reliability = Reliability::BestEffort; + nmsg.reliability = Reliability::BestEffort; batch.encode((&nmsg, &frame)).unwrap(); assert_ne!(batch.len(), 0); nmsgs_in.push(nmsg.clone()); From 168a80448991f1234f03267c0c150444e8fb772e Mon Sep 17 00:00:00 2001 From: Oussama Teffahi Date: Thu, 29 Aug 2024 18:24:15 +0200 Subject: [PATCH 06/33] Change defrag errors to log instead of closing transport --- .../src/common/defragmentation.rs | 6 +++- io/zenoh-transport/src/multicast/rx.rs | 16 +++++----- .../src/unicast/universal/rx.rs | 30 +++++++++---------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/io/zenoh-transport/src/common/defragmentation.rs b/io/zenoh-transport/src/common/defragmentation.rs index 476fad632c..481f4b00bd 100644 --- a/io/zenoh-transport/src/common/defragmentation.rs +++ b/io/zenoh-transport/src/common/defragmentation.rs @@ -66,7 +66,11 @@ impl DefragBuffer { pub(crate) fn push(&mut self, sn: TransportSn, zslice: ZSlice) -> ZResult<()> { if sn != self.sn.get() { self.clear(); - bail!("Expected SN {}, received {}", self.sn.get(), sn) + bail!( + "Defragmentation SN error: expected SN {}, received {}", + self.sn.get(), + sn + ) } let new_len = self.len + zslice.len(); diff --git a/io/zenoh-transport/src/multicast/rx.rs b/io/zenoh-transport/src/multicast/rx.rs index 93dc3c727a..0f0288ee21 100644 --- a/io/zenoh-transport/src/multicast/rx.rs +++ b/io/zenoh-transport/src/multicast/rx.rs @@ -207,18 +207,20 @@ impl TransportMulticastInner { if guard.defrag.is_empty() { let _ = guard.defrag.sync(sn); } - guard.defrag.push(sn, payload)?; - if !more { + if let Err(e) = guard.defrag.push(sn, payload) { + tracing::trace!("{}", e); + } else if !more { // When shared-memory feature is disabled, msg does not need to be mutable - let msg = guard.defrag.defragment().ok_or_else(|| { - zerror!( + if let Some(msg) = guard.defrag.defragment() { + return self.trigger_callback(msg, peer); + } else { + tracing::trace!( "Transport: {}. Peer: {}. Priority: {:?}. Defragmentation error.", self.manager.config.zid, peer.zid, priority - ) - })?; - return self.trigger_callback(msg, peer); + ); + } } Ok(()) diff --git a/io/zenoh-transport/src/unicast/universal/rx.rs b/io/zenoh-transport/src/unicast/universal/rx.rs index afd8e114d7..7c207b160c 100644 --- a/io/zenoh-transport/src/unicast/universal/rx.rs +++ b/io/zenoh-transport/src/unicast/universal/rx.rs @@ -145,23 +145,23 @@ impl TransportUnicastUniversal { if guard.defrag.is_empty() { let _ = guard.defrag.sync(sn); } - guard.defrag.push(sn, payload)?; - if !more { + if let Err(e) = guard.defrag.push(sn, payload) { + tracing::trace!("{}", e); + } else if !more { // When shared-memory feature is disabled, msg does not need to be mutable - let msg = guard - .defrag - .defragment() - .ok_or_else(|| zerror!("Transport: {}. Defragmentation error.", self.config.zid))?; - - let callback = zread!(self.callback).clone(); - if let Some(callback) = callback.as_ref() { - return self.trigger_callback(callback.as_ref(), msg); + if let Some(msg) = guard.defrag.defragment() { + let callback = zread!(self.callback).clone(); + if let Some(callback) = callback.as_ref() { + return self.trigger_callback(callback.as_ref(), msg); + } else { + tracing::debug!( + "Transport: {}. No callback available, dropping messages: {:?}", + self.config.zid, + msg + ); + } } else { - tracing::debug!( - "Transport: {}. No callback available, dropping messages: {:?}", - self.config.zid, - msg - ); + tracing::trace!("Transport: {}. Defragmentation error.", self.config.zid); } } From 5114c33e205c2c9574246a39c24d669d9ad8bc04 Mon Sep 17 00:00:00 2001 From: Oussama Teffahi Date: Fri, 30 Aug 2024 15:34:27 +0200 Subject: [PATCH 07/33] Fix messages with old SN not being dropped --- io/zenoh-transport/src/multicast/rx.rs | 55 ++++++------- .../src/unicast/universal/rx.rs | 79 +++++++++---------- 2 files changed, 62 insertions(+), 72 deletions(-) diff --git a/io/zenoh-transport/src/multicast/rx.rs b/io/zenoh-transport/src/multicast/rx.rs index 0f0288ee21..ca607be493 100644 --- a/io/zenoh-transport/src/multicast/rx.rs +++ b/io/zenoh-transport/src/multicast/rx.rs @@ -166,10 +166,10 @@ impl TransportMulticastInner { Reliability::BestEffort => zlock!(c.best_effort), }; - self.verify_sn(sn, &mut guard)?; - - for msg in payload.drain(..) { - self.trigger_callback(msg, peer)?; + if self.verify_sn(sn, &mut guard)? { + for msg in payload.drain(..) { + self.trigger_callback(msg, peer)?; + } } Ok(()) } @@ -202,24 +202,24 @@ impl TransportMulticastInner { Reliability::BestEffort => zlock!(c.best_effort), }; - self.verify_sn(sn, &mut guard)?; - - if guard.defrag.is_empty() { - let _ = guard.defrag.sync(sn); - } - if let Err(e) = guard.defrag.push(sn, payload) { - tracing::trace!("{}", e); - } else if !more { - // When shared-memory feature is disabled, msg does not need to be mutable - if let Some(msg) = guard.defrag.defragment() { - return self.trigger_callback(msg, peer); - } else { - tracing::trace!( - "Transport: {}. Peer: {}. Priority: {:?}. Defragmentation error.", - self.manager.config.zid, - peer.zid, - priority - ); + if self.verify_sn(sn, &mut guard)? { + if guard.defrag.is_empty() { + let _ = guard.defrag.sync(sn); + } + if let Err(e) = guard.defrag.push(sn, payload) { + tracing::trace!("{}", e); + } else if !more { + // When shared-memory feature is disabled, msg does not need to be mutable + if let Some(msg) = guard.defrag.defragment() { + return self.trigger_callback(msg, peer); + } else { + tracing::trace!( + "Transport: {}. Peer: {}. Priority: {:?}. Defragmentation error.", + self.manager.config.zid, + peer.zid, + priority + ); + } } } @@ -230,7 +230,7 @@ impl TransportMulticastInner { &self, sn: TransportSn, guard: &mut MutexGuard<'_, TransportChannelRx>, - ) -> ZResult<()> { + ) -> ZResult { let precedes = guard.sn.precedes(sn)?; if !precedes { tracing::debug!( @@ -239,19 +239,14 @@ impl TransportMulticastInner { sn, guard.sn.next() ); - // Drop the fragments if needed - if !guard.defrag.is_empty() { - guard.defrag.clear(); - } - // Keep reading - return Ok(()); + return Ok(false); } // Set will always return OK because we have already checked // with precedes() that the sn has the right resolution let _ = guard.sn.set(sn); - Ok(()) + Ok(true) } pub(super) fn read_messages( diff --git a/io/zenoh-transport/src/unicast/universal/rx.rs b/io/zenoh-transport/src/unicast/universal/rx.rs index 7c207b160c..f826c054d4 100644 --- a/io/zenoh-transport/src/unicast/universal/rx.rs +++ b/io/zenoh-transport/src/unicast/universal/rx.rs @@ -97,19 +97,19 @@ impl TransportUnicastUniversal { Reliability::BestEffort => zlock!(c.best_effort), }; - self.verify_sn(sn, &mut guard)?; - - let callback = zread!(self.callback).clone(); - if let Some(callback) = callback.as_ref() { - for msg in payload.drain(..) { - self.trigger_callback(callback.as_ref(), msg)?; + if self.verify_sn(sn, &mut guard)? { + let callback = zread!(self.callback).clone(); + if let Some(callback) = callback.as_ref() { + for msg in payload.drain(..) { + self.trigger_callback(callback.as_ref(), msg)?; + } + } else { + tracing::debug!( + "Transport: {}. No callback available, dropping messages: {:?}", + self.config.zid, + payload + ); } - } else { - tracing::debug!( - "Transport: {}. No callback available, dropping messages: {:?}", - self.config.zid, - payload - ); } Ok(()) } @@ -140,28 +140,28 @@ impl TransportUnicastUniversal { Reliability::BestEffort => zlock!(c.best_effort), }; - self.verify_sn(sn, &mut guard)?; - - if guard.defrag.is_empty() { - let _ = guard.defrag.sync(sn); - } - if let Err(e) = guard.defrag.push(sn, payload) { - tracing::trace!("{}", e); - } else if !more { - // When shared-memory feature is disabled, msg does not need to be mutable - if let Some(msg) = guard.defrag.defragment() { - let callback = zread!(self.callback).clone(); - if let Some(callback) = callback.as_ref() { - return self.trigger_callback(callback.as_ref(), msg); + if self.verify_sn(sn, &mut guard)? { + if guard.defrag.is_empty() { + let _ = guard.defrag.sync(sn); + } + if let Err(e) = guard.defrag.push(sn, payload) { + tracing::trace!("{}", e); + } else if !more { + // When shared-memory feature is disabled, msg does not need to be mutable + if let Some(msg) = guard.defrag.defragment() { + let callback = zread!(self.callback).clone(); + if let Some(callback) = callback.as_ref() { + return self.trigger_callback(callback.as_ref(), msg); + } else { + tracing::debug!( + "Transport: {}. No callback available, dropping messages: {:?}", + self.config.zid, + msg + ); + } } else { - tracing::debug!( - "Transport: {}. No callback available, dropping messages: {:?}", - self.config.zid, - msg - ); + tracing::trace!("Transport: {}. Defragmentation error.", self.config.zid); } - } else { - tracing::trace!("Transport: {}. Defragmentation error.", self.config.zid); } } @@ -172,24 +172,19 @@ impl TransportUnicastUniversal { &self, sn: TransportSn, guard: &mut MutexGuard<'_, TransportChannelRx>, - ) -> ZResult<()> { + ) -> ZResult { let precedes = guard.sn.roll(sn)?; if !precedes { - tracing::debug!( + tracing::trace!( "Transport: {}. Frame with invalid SN dropped: {}. Expected: {}.", self.config.zid, sn, - guard.sn.get() + guard.sn.next() ); - // Drop the fragments if needed - if !guard.defrag.is_empty() { - guard.defrag.clear(); - } - // Keep reading - return Ok(()); + return Ok(false); } - Ok(()) + Ok(true) } pub(super) fn read_messages(&self, mut batch: RBatch, link: &Link) -> ZResult<()> { From 7206fdc0eec8294d53cdbdc0122be2a3da1065e4 Mon Sep 17 00:00:00 2001 From: Oussama Teffahi Date: Fri, 30 Aug 2024 16:31:38 +0200 Subject: [PATCH 08/33] Remove failure check in defrag tests --- .../tests/unicast_defragmentation.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/io/zenoh-transport/tests/unicast_defragmentation.rs b/io/zenoh-transport/tests/unicast_defragmentation.rs index fc54180c96..03a9ed6ee8 100644 --- a/io/zenoh-transport/tests/unicast_defragmentation.rs +++ b/io/zenoh-transport/tests/unicast_defragmentation.rs @@ -93,20 +93,6 @@ async fn run(endpoint: &EndPoint, channel: Channel, msg_size: usize) { ); client_transport.schedule(message.clone()).unwrap(); - // Wait that the client transport has been closed - ztimeout!(async { - while client_transport.get_zid().is_ok() { - tokio::time::sleep(SLEEP).await; - } - }); - - // Wait on the router manager that the transport has been closed - ztimeout!(async { - while !router_manager.get_transports_unicast().await.is_empty() { - tokio::time::sleep(SLEEP).await; - } - }); - // Stop the locators on the manager println!("Del locator: {endpoint}"); ztimeout!(router_manager.del_listener(endpoint)).unwrap(); From c434f69f289843941284327b0644e51be0cd879d Mon Sep 17 00:00:00 2001 From: Oussama Teffahi Date: Fri, 30 Aug 2024 16:32:54 +0200 Subject: [PATCH 09/33] Wait for message to be sent in defrag test --- io/zenoh-transport/tests/unicast_defragmentation.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/io/zenoh-transport/tests/unicast_defragmentation.rs b/io/zenoh-transport/tests/unicast_defragmentation.rs index 03a9ed6ee8..5df569eff4 100644 --- a/io/zenoh-transport/tests/unicast_defragmentation.rs +++ b/io/zenoh-transport/tests/unicast_defragmentation.rs @@ -93,6 +93,9 @@ async fn run(endpoint: &EndPoint, channel: Channel, msg_size: usize) { ); client_transport.schedule(message.clone()).unwrap(); + // wait a little bit for the message to be sent + tokio::time::sleep(SLEEP).await; + // Stop the locators on the manager println!("Del locator: {endpoint}"); ztimeout!(router_manager.del_listener(endpoint)).unwrap(); From bafbe617fc48d49f4bf6ecff9de48acdd4c14be9 Mon Sep 17 00:00:00 2001 From: Oussama Teffahi Date: Mon, 2 Sep 2024 17:31:33 +0200 Subject: [PATCH 10/33] Remove if-statement nesting --- io/zenoh-transport/src/multicast/rx.rs | 52 ++++++++------ .../src/unicast/universal/rx.rs | 72 ++++++++++--------- 2 files changed, 70 insertions(+), 54 deletions(-) diff --git a/io/zenoh-transport/src/multicast/rx.rs b/io/zenoh-transport/src/multicast/rx.rs index ca607be493..8562d5b3eb 100644 --- a/io/zenoh-transport/src/multicast/rx.rs +++ b/io/zenoh-transport/src/multicast/rx.rs @@ -166,11 +166,14 @@ impl TransportMulticastInner { Reliability::BestEffort => zlock!(c.best_effort), }; - if self.verify_sn(sn, &mut guard)? { - for msg in payload.drain(..) { - self.trigger_callback(msg, peer)?; - } + if !self.verify_sn(sn, &mut guard)? { + // Drop invalid message and continue + return Ok(()); + } + for msg in payload.drain(..) { + self.trigger_callback(msg, peer)?; } + Ok(()) } @@ -202,24 +205,29 @@ impl TransportMulticastInner { Reliability::BestEffort => zlock!(c.best_effort), }; - if self.verify_sn(sn, &mut guard)? { - if guard.defrag.is_empty() { - let _ = guard.defrag.sync(sn); - } - if let Err(e) = guard.defrag.push(sn, payload) { - tracing::trace!("{}", e); - } else if !more { - // When shared-memory feature is disabled, msg does not need to be mutable - if let Some(msg) = guard.defrag.defragment() { - return self.trigger_callback(msg, peer); - } else { - tracing::trace!( - "Transport: {}. Peer: {}. Priority: {:?}. Defragmentation error.", - self.manager.config.zid, - peer.zid, - priority - ); - } + if !self.verify_sn(sn, &mut guard)? { + // Drop invalid message and continue + return Ok(()); + } + if guard.defrag.is_empty() { + let _ = guard.defrag.sync(sn); + } + if let Err(e) = guard.defrag.push(sn, payload) { + // Defrag errors don't close transport + tracing::trace!("{}", e); + return Ok(()); + } + if !more { + // When shared-memory feature is disabled, msg does not need to be mutable + if let Some(msg) = guard.defrag.defragment() { + return self.trigger_callback(msg, peer); + } else { + tracing::trace!( + "Transport: {}. Peer: {}. Priority: {:?}. Defragmentation error.", + self.manager.config.zid, + peer.zid, + priority + ); } } diff --git a/io/zenoh-transport/src/unicast/universal/rx.rs b/io/zenoh-transport/src/unicast/universal/rx.rs index f826c054d4..e69a305876 100644 --- a/io/zenoh-transport/src/unicast/universal/rx.rs +++ b/io/zenoh-transport/src/unicast/universal/rx.rs @@ -97,20 +97,23 @@ impl TransportUnicastUniversal { Reliability::BestEffort => zlock!(c.best_effort), }; - if self.verify_sn(sn, &mut guard)? { - let callback = zread!(self.callback).clone(); - if let Some(callback) = callback.as_ref() { - for msg in payload.drain(..) { - self.trigger_callback(callback.as_ref(), msg)?; - } - } else { - tracing::debug!( - "Transport: {}. No callback available, dropping messages: {:?}", - self.config.zid, - payload - ); + if !self.verify_sn(sn, &mut guard)? { + // Drop invalid message and continue + return Ok(()); + } + let callback = zread!(self.callback).clone(); + if let Some(callback) = callback.as_ref() { + for msg in payload.drain(..) { + self.trigger_callback(callback.as_ref(), msg)?; } + } else { + tracing::debug!( + "Transport: {}. No callback available, dropping messages: {:?}", + self.config.zid, + payload + ); } + Ok(()) } @@ -140,28 +143,33 @@ impl TransportUnicastUniversal { Reliability::BestEffort => zlock!(c.best_effort), }; - if self.verify_sn(sn, &mut guard)? { - if guard.defrag.is_empty() { - let _ = guard.defrag.sync(sn); - } - if let Err(e) = guard.defrag.push(sn, payload) { - tracing::trace!("{}", e); - } else if !more { - // When shared-memory feature is disabled, msg does not need to be mutable - if let Some(msg) = guard.defrag.defragment() { - let callback = zread!(self.callback).clone(); - if let Some(callback) = callback.as_ref() { - return self.trigger_callback(callback.as_ref(), msg); - } else { - tracing::debug!( - "Transport: {}. No callback available, dropping messages: {:?}", - self.config.zid, - msg - ); - } + if !self.verify_sn(sn, &mut guard)? { + // Drop invalid message and continue + return Ok(()); + } + if guard.defrag.is_empty() { + let _ = guard.defrag.sync(sn); + } + if let Err(e) = guard.defrag.push(sn, payload) { + // Defrag errors don't close transport + tracing::trace!("{}", e); + return Ok(()); + } + if !more { + // When shared-memory feature is disabled, msg does not need to be mutable + if let Some(msg) = guard.defrag.defragment() { + let callback = zread!(self.callback).clone(); + if let Some(callback) = callback.as_ref() { + return self.trigger_callback(callback.as_ref(), msg); } else { - tracing::trace!("Transport: {}. Defragmentation error.", self.config.zid); + tracing::debug!( + "Transport: {}. No callback available, dropping messages: {:?}", + self.config.zid, + msg + ); } + } else { + tracing::trace!("Transport: {}. Defragmentation error.", self.config.zid); } } From 96cefa548ffbf65d8c92198b7c355dfaabe44f89 Mon Sep 17 00:00:00 2001 From: Oussama Teffahi Date: Mon, 2 Sep 2024 17:31:51 +0200 Subject: [PATCH 11/33] Remove deprecated defragmentation test --- .../tests/unicast_defragmentation.rs | 217 ------------------ 1 file changed, 217 deletions(-) delete mode 100644 io/zenoh-transport/tests/unicast_defragmentation.rs diff --git a/io/zenoh-transport/tests/unicast_defragmentation.rs b/io/zenoh-transport/tests/unicast_defragmentation.rs deleted file mode 100644 index 5df569eff4..0000000000 --- a/io/zenoh-transport/tests/unicast_defragmentation.rs +++ /dev/null @@ -1,217 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// -use std::{convert::TryFrom, sync::Arc, time::Duration}; - -use zenoh_core::ztimeout; -use zenoh_protocol::{ - core::{ - Channel, CongestionControl, Encoding, EndPoint, Priority, Reliability, WhatAmI, - ZenohIdProto, - }, - network::{ - push::{ - ext::{NodeIdType, QoSType}, - Push, - }, - NetworkMessage, - }, - zenoh::Put, -}; -use zenoh_transport::{DummyTransportEventHandler, TransportManager}; - -const TIMEOUT: Duration = Duration::from_secs(60); -const SLEEP: Duration = Duration::from_secs(1); - -const MSG_SIZE: usize = 131_072; -const MSG_DEFRAG_BUF: usize = 128_000; - -async fn run(endpoint: &EndPoint, channel: Channel, msg_size: usize) { - // Define client and router IDs - let client_id = ZenohIdProto::try_from([1]).unwrap(); - let router_id = ZenohIdProto::try_from([2]).unwrap(); - - // Create the router transport manager - let router_manager = TransportManager::builder() - .zid(router_id) - .whatami(WhatAmI::Router) - .defrag_buff_size(MSG_DEFRAG_BUF) - .build(Arc::new(DummyTransportEventHandler)) - .unwrap(); - - // Create the client transport manager - let client_manager = TransportManager::builder() - .whatami(WhatAmI::Client) - .zid(client_id) - .defrag_buff_size(MSG_DEFRAG_BUF) - .build(Arc::new(DummyTransportEventHandler)) - .unwrap(); - - // Create the listener on the router - println!("Add locator: {endpoint}"); - let _ = ztimeout!(router_manager.add_listener(endpoint.clone())).unwrap(); - - // Create an empty transport with the client - // Open transport -> This should be accepted - println!("Opening transport with {endpoint}"); - let _ = ztimeout!(client_manager.open_transport_unicast(endpoint.clone())).unwrap(); - - let client_transport = ztimeout!(client_manager.get_transport_unicast(&router_id)).unwrap(); - - // Create the message to send - let message: NetworkMessage = Push { - wire_expr: "test".into(), - ext_qos: QoSType::new(channel.priority, CongestionControl::Block, false), - ext_tstamp: None, - ext_nodeid: NodeIdType::DEFAULT, - payload: Put { - payload: vec![0u8; msg_size].into(), - timestamp: None, - encoding: Encoding::empty(), - ext_sinfo: None, - #[cfg(feature = "shared-memory")] - ext_shm: None, - ext_attachment: None, - ext_unknown: vec![], - } - .into(), - } - .into(); - - println!( - "Sending message of {msg_size} bytes while defragmentation buffer size is {MSG_DEFRAG_BUF} bytes" - ); - client_transport.schedule(message.clone()).unwrap(); - - // wait a little bit for the message to be sent - tokio::time::sleep(SLEEP).await; - - // Stop the locators on the manager - println!("Del locator: {endpoint}"); - ztimeout!(router_manager.del_listener(endpoint)).unwrap(); - - // Wait a little bit - ztimeout!(async { - while !router_manager.get_listeners().await.is_empty() { - tokio::time::sleep(SLEEP).await; - } - }); - - tokio::time::sleep(SLEEP).await; - - ztimeout!(router_manager.close()); - ztimeout!(client_manager.close()); - - // Wait a little bit - tokio::time::sleep(SLEEP).await; -} - -#[cfg(feature = "transport_tcp")] -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] -async fn transport_unicast_defragmentation_tcp_only() { - zenoh_util::try_init_log_from_env(); - - // Define the locators - let endpoint: EndPoint = format!("tcp/127.0.0.1:{}", 11000).parse().unwrap(); - // Define the reliability and congestion control - let channel = [ - Channel { - priority: Priority::DEFAULT, - reliability: Reliability::Reliable, - }, - Channel { - priority: Priority::DEFAULT, - reliability: Reliability::BestEffort, - }, - Channel { - priority: Priority::RealTime, - reliability: Reliability::Reliable, - }, - Channel { - priority: Priority::RealTime, - reliability: Reliability::BestEffort, - }, - ]; - // Run - for ch in channel.iter() { - run(&endpoint, *ch, MSG_SIZE).await; - } -} - -#[cfg(feature = "transport_ws")] -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] -#[ignore] -async fn transport_unicast_defragmentation_ws_only() { - zenoh_util::try_init_log_from_env(); - - // Define the locators - let endpoint: EndPoint = format!("ws/127.0.0.1:{}", 11010).parse().unwrap(); - // Define the reliability and congestion control - let channel = [ - Channel { - priority: Priority::DEFAULT, - reliability: Reliability::Reliable, - }, - Channel { - priority: Priority::DEFAULT, - reliability: Reliability::BestEffort, - }, - Channel { - priority: Priority::RealTime, - reliability: Reliability::Reliable, - }, - Channel { - priority: Priority::RealTime, - reliability: Reliability::BestEffort, - }, - ]; - // Run - for ch in channel.iter() { - run(&endpoint, *ch, MSG_SIZE).await; - } -} - -#[cfg(feature = "transport_unixpipe")] -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] -#[ignore] -async fn transport_unicast_defragmentation_unixpipe_only() { - zenoh_util::try_init_log_from_env(); - - // Define the locators - let endpoint: EndPoint = "unixpipe/transport_unicast_defragmentation_unixpipe_only" - .parse() - .unwrap(); - // Define the reliability and congestion control - let channel = [ - Channel { - priority: Priority::DEFAULT, - reliability: Reliability::Reliable, - }, - Channel { - priority: Priority::DEFAULT, - reliability: Reliability::BestEffort, - }, - Channel { - priority: Priority::RealTime, - reliability: Reliability::Reliable, - }, - Channel { - priority: Priority::RealTime, - reliability: Reliability::BestEffort, - }, - ]; - // Run - for ch in channel.iter() { - run(&endpoint, *ch, MSG_SIZE).await; - } -} From a7d03b7f575c027914a8fe3df396b3bd831b6fa8 Mon Sep 17 00:00:00 2001 From: Mahmoud Mazouz Date: Tue, 3 Sep 2024 11:10:15 +0000 Subject: [PATCH 12/33] Parse `backend_search_dirs` as a list of paths --- plugins/zenoh-backend-traits/src/config.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/zenoh-backend-traits/src/config.rs b/plugins/zenoh-backend-traits/src/config.rs index e440e3014e..b791ba5c1a 100644 --- a/plugins/zenoh-backend-traits/src/config.rs +++ b/plugins/zenoh-backend-traits/src/config.rs @@ -164,6 +164,8 @@ impl + AsRef, V: AsObject> TryFrom<(S, &V)> for PluginConfi }) }) .unwrap_or(Ok(true))?; + // TODO(fuzzypixelz): refactor this function's interface to get access to the configuration + // source, this we can support spec syntax in the lib search dir. let backend_search_dirs = match value.get("backend_search_dirs") { Some(serde_json::Value::String(path)) => LibSearchDirs::from_paths(&[path.clone()]), Some(serde_json::Value::Array(paths)) => { @@ -174,7 +176,7 @@ impl + AsRef, V: AsObject> TryFrom<(S, &V)> for PluginConfi }; specs.push(path.clone()); } - LibSearchDirs::from_specs(&specs)? + LibSearchDirs::from_paths(&specs) } None => LibSearchDirs::default(), _ => bail!("`backend_search_dirs` field of {}'s configuration must be a string or array of strings", name.as_ref()) From b21ce07194f03459de5245502b6b50e924f636bf Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Tue, 3 Sep 2024 15:31:14 +0200 Subject: [PATCH 13/33] Change Reliability default to Reliable --- commons/zenoh-protocol/src/core/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commons/zenoh-protocol/src/core/mod.rs b/commons/zenoh-protocol/src/core/mod.rs index ebf1bb7f85..629357e339 100644 --- a/commons/zenoh-protocol/src/core/mod.rs +++ b/commons/zenoh-protocol/src/core/mod.rs @@ -346,12 +346,12 @@ impl TryFrom for Priority { #[repr(u8)] pub enum Reliability { #[default] - BestEffort, Reliable, + BestEffort, } impl Reliability { - pub const DEFAULT: Self = Self::BestEffort; + pub const DEFAULT: Self = Self::Reliable; #[cfg(feature = "test")] pub fn rand() -> Self { From e1cd9cbb39f1e7eb8a708a64cd3e8b9c099fdffc Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Tue, 3 Sep 2024 16:01:55 +0200 Subject: [PATCH 14/33] Fix merge --- zenoh/src/api/session.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index be727c80f4..26704d378a 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -39,7 +39,8 @@ use zenoh_protocol::network::{ use zenoh_protocol::{ core::{ key_expr::{keyexpr, OwnedKeyExpr}, - AtomicExprId, CongestionControl, EntityId, ExprId, Parameters, WireExpr, EMPTY_EXPR_ID, + AtomicExprId, CongestionControl, EntityId, ExprId, Parameters, Reliability, WireExpr, + EMPTY_EXPR_ID, }, network::{ self, @@ -101,8 +102,6 @@ use crate::net::{ routing::dispatcher::face::Face, runtime::{Runtime, RuntimeBuilder}, }; -#[cfg(feature = "unstable")] -use crate::pubsub::Reliability; zconfigurable! { pub(crate) static ref API_DATA_RECEPTION_CHANNEL_SIZE: usize = 256; From 0a911f3a6015f613e846a5ee242e9a61b8675c96 Mon Sep 17 00:00:00 2001 From: oteffahi <70609372+oteffahi@users.noreply.github.com> Date: Tue, 3 Sep 2024 19:15:31 +0200 Subject: [PATCH 15/33] Fix storage error when keyexpr equals the configured `strip_prefix` (#1351) --- plugins/zenoh-plugin-storage-manager/src/lib.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/plugins/zenoh-plugin-storage-manager/src/lib.rs b/plugins/zenoh-plugin-storage-manager/src/lib.rs index ac778f3633..77e53cc80d 100644 --- a/plugins/zenoh-plugin-storage-manager/src/lib.rs +++ b/plugins/zenoh-plugin-storage-manager/src/lib.rs @@ -443,14 +443,16 @@ pub fn strip_prefix( ); } - match key_expr.strip_prefix(prefix).as_slice() { - [stripped_key_expr] => { - if stripped_key_expr.is_empty() { - return Ok(None); - } + // `key_expr.strip_prefix` returns empty vec if `key_expr == prefix`, + // but also returns empty vec if `prefix` is not a prefix to `key_expr`. + // First case needs to be handled before calling `key_expr.strip_prefix` + if key_expr.as_str().eq(prefix.as_str()) { + return Ok(None); + } - OwnedKeyExpr::from_str(stripped_key_expr).map(Some) - } + match key_expr.strip_prefix(prefix).as_slice() { + // NOTE: `stripped_key_expr.is_empty()` should be impossible as "" is not a valid key expression + [stripped_key_expr] => OwnedKeyExpr::from_str(stripped_key_expr).map(Some), _ => bail!("Failed to strip prefix < {} > from: {}", prefix, key_expr), } } From 627a71db156fa784404981e8dbc3eb843d6abb22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:51:19 +0000 Subject: [PATCH 16/33] chore(deps): bump quinn-proto from 0.11.3 to 0.11.8 Bumps [quinn-proto](https://github.com/quinn-rs/quinn) from 0.11.3 to 0.11.8. - [Release notes](https://github.com/quinn-rs/quinn/releases) - [Commits](https://github.com/quinn-rs/quinn/compare/quinn-proto-0.11.3...quinn-proto-0.11.8) --- updated-dependencies: - dependency-name: quinn-proto dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Cargo.lock | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8768c911cf..2f140121fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3079,7 +3079,7 @@ dependencies = [ "pin-project-lite 0.2.13", "quinn-proto", "quinn-udp", - "rustc-hash 2.0.0", + "rustc-hash", "rustls", "socket2 0.5.7", "thiserror", @@ -3089,14 +3089,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand 0.8.5", "ring", - "rustc-hash 1.1.0", + "rustc-hash", "rustls", "rustls-platform-verifier", "slab", @@ -3416,12 +3416,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.0.0" From 118c441663f4d09257dcab945d3c1e45158f64ee Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Wed, 4 Sep 2024 11:24:43 +0200 Subject: [PATCH 17/33] Improve batch tests Co-authored-by: Luca Cominardi --- io/zenoh-transport/src/common/batch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/zenoh-transport/src/common/batch.rs b/io/zenoh-transport/src/common/batch.rs index 715d487b8c..cc18ad36c4 100644 --- a/io/zenoh-transport/src/common/batch.rs +++ b/io/zenoh-transport/src/common/batch.rs @@ -601,7 +601,7 @@ mod tests { sn: 0, ext_qos: frame::ext::QoSType::DEFAULT, }; - nmsg.reliability = Reliability::Reliable; + nmsg.reliability = frame.reliability; // Serialize with a frame batch.encode((&nmsg, &frame)).unwrap(); From b6bf33443966f46f543cad3a7465a9e5dd38ee35 Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Wed, 4 Sep 2024 11:24:53 +0200 Subject: [PATCH 18/33] Improve batch tests Co-authored-by: Luca Cominardi --- io/zenoh-transport/src/common/batch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/zenoh-transport/src/common/batch.rs b/io/zenoh-transport/src/common/batch.rs index cc18ad36c4..578adf22d1 100644 --- a/io/zenoh-transport/src/common/batch.rs +++ b/io/zenoh-transport/src/common/batch.rs @@ -609,7 +609,7 @@ mod tests { nmsgs_in.push(nmsg.clone()); frame.reliability = Reliability::BestEffort; - nmsg.reliability = Reliability::BestEffort; + nmsg.reliability = frame.reliability; batch.encode((&nmsg, &frame)).unwrap(); assert_ne!(batch.len(), 0); nmsgs_in.push(nmsg.clone()); From 38ef6106460be3ffa80bf7eabf21a806a40116e4 Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Wed, 4 Sep 2024 11:25:22 +0200 Subject: [PATCH 19/33] Improve publisher reliability doc. Co-authored-by: Luca Cominardi --- zenoh/src/api/builders/publisher.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index 0404838a04..4333f68846 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -310,6 +310,8 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { } /// Change the `reliability`` to apply when routing the data. + /// NOTE: Currently `reliability` does not trigger any data retransmission on the wire. + /// It is rather used as a marker on the wire and it may be used to select the best link available (e.g. TCP for reliable data and UDP for best effort data). #[zenoh_macros::unstable] #[inline] pub fn reliability(self, reliability: Reliability) -> Self { From 2128f14d4c1d2ef3a71ea10f6d72305a99b7f9ff Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Wed, 4 Sep 2024 11:25:35 +0200 Subject: [PATCH 20/33] Improve publisher reliability doc. Co-authored-by: Luca Cominardi --- zenoh/src/api/builders/publisher.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index 4333f68846..457041589a 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -114,6 +114,8 @@ impl PublicationBuilder, T> { self } /// Change the `reliability` to apply when routing the data. + /// NOTE: Currently `reliability` does not trigger any data retransmission on the wire. + /// It is rather used as a marker on the wire and it may be used to select the best link available (e.g. TCP for reliable data and UDP for best effort data). #[zenoh_macros::unstable] #[inline] pub fn reliability(self, reliability: Reliability) -> Self { From 43ec70ebf99258538f590bcdd70d152429f66e7f Mon Sep 17 00:00:00 2001 From: OlivierHecart Date: Wed, 4 Sep 2024 11:27:52 +0200 Subject: [PATCH 21/33] Code format --- zenoh/src/api/builders/publisher.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index 457041589a..8a6961ac55 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -114,7 +114,7 @@ impl PublicationBuilder, T> { self } /// Change the `reliability` to apply when routing the data. - /// NOTE: Currently `reliability` does not trigger any data retransmission on the wire. + /// NOTE: Currently `reliability` does not trigger any data retransmission on the wire. /// It is rather used as a marker on the wire and it may be used to select the best link available (e.g. TCP for reliable data and UDP for best effort data). #[zenoh_macros::unstable] #[inline] @@ -312,7 +312,7 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { } /// Change the `reliability`` to apply when routing the data. - /// NOTE: Currently `reliability` does not trigger any data retransmission on the wire. + /// NOTE: Currently `reliability` does not trigger any data retransmission on the wire. /// It is rather used as a marker on the wire and it may be used to select the best link available (e.g. TCP for reliable data and UDP for best effort data). #[zenoh_macros::unstable] #[inline] From 147ebc38a9968eaaf16919cb5f71d27800b76315 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 28 Aug 2024 07:07:38 +0200 Subject: [PATCH 22/33] feat!: bind callback subscriber/queryable to session lifetime To determine if the entity is callback-only, the only elegant way I've found is the rule "handler is ZST means callback-only". Unless users starts writing fancy implementations, it should be correct 100% of the time. Session entities now uses weak references, except publishers because it would impact performances. Weak references also solves the issue of mass undeclarations before closing the session (when the session is an `Arc`), except for publishers. `Undeclarable` trait has been refactored a little bit to better match its use in the code. --- examples/examples/z_sub_thr.rs | 4 +- zenoh/src/api/key_expr.rs | 5 +- zenoh/src/api/liveliness.rs | 59 +++++----- zenoh/src/api/publisher.rs | 97 ++++++---------- zenoh/src/api/queryable.rs | 201 ++++++++++++++++++--------------- zenoh/src/api/session.rs | 69 ++++++----- zenoh/src/api/subscriber.rs | 183 +++++++++++++----------------- zenoh/src/lib.rs | 4 +- 8 files changed, 297 insertions(+), 325 deletions(-) diff --git a/examples/examples/z_sub_thr.rs b/examples/examples/z_sub_thr.rs index 78626d1d1d..460a8dfe73 100644 --- a/examples/examples/z_sub_thr.rs +++ b/examples/examples/z_sub_thr.rs @@ -87,9 +87,7 @@ fn main() { } }) .wait() - .unwrap() - // Make the subscriber run in background, until the session is closed. - .background(); + .unwrap(); println!("Press CTRL-C to quit..."); std::thread::park(); diff --git a/zenoh/src/api/key_expr.rs b/zenoh/src/api/key_expr.rs index fc472e0db3..bde77f5d32 100644 --- a/zenoh/src/api/key_expr.rs +++ b/zenoh/src/api/key_expr.rs @@ -549,8 +549,9 @@ impl<'a> KeyExpr<'a> { } } -impl<'a> UndeclarableSealed<&'a Session, KeyExprUndeclaration<'a>> for KeyExpr<'a> { - fn undeclare_inner(self, session: &'a Session) -> KeyExprUndeclaration<'a> { +impl<'a> UndeclarableSealed<&'a Session> for KeyExpr<'a> { + type Undeclaration = KeyExprUndeclaration<'a>; + fn undeclare_inner(self, session: &'a Session) -> Self::Undeclaration { KeyExprUndeclaration { session, expr: self, diff --git a/zenoh/src/api/liveliness.rs b/zenoh/src/api/liveliness.rs index 64f87c6de5..bb068b4e52 100644 --- a/zenoh/src/api/liveliness.rs +++ b/zenoh/src/api/liveliness.rs @@ -15,10 +15,12 @@ use std::{ convert::TryInto, future::{IntoFuture, Ready}, + mem::size_of, sync::Arc, time::Duration, }; +use tracing::error; use zenoh_config::unwrap_or_default; use zenoh_core::{Resolvable, Resolve, Result as ZResult, Wait}; @@ -31,6 +33,7 @@ use super::{ subscriber::{Subscriber, SubscriberInner}, Id, }; +use crate::api::session::WeakSessionRef; /// A structure with functions to declare a /// [`LivelinessToken`](LivelinessToken), query @@ -254,7 +257,7 @@ impl Wait for LivelinessTokenBuilder<'_, '_> { session .declare_liveliness_inner(&key_expr) .map(|tok_state| LivelinessToken { - session, + session: session.into(), state: tok_state, undeclare_on_drop: true, }) @@ -288,7 +291,7 @@ pub(crate) struct LivelinessTokenState { /// that declared the token has Zenoh connectivity with the Zenoh application /// that monitors it. /// -/// `LivelinessTokens` are automatically undeclared when dropped. +/// Liveliness tokens are automatically undeclared when dropped. /// /// # Examples /// ```no_run @@ -307,12 +310,12 @@ pub(crate) struct LivelinessTokenState { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessToken<'a> { - pub(crate) session: SessionRef<'a>, - pub(crate) state: Arc, + session: WeakSessionRef<'a>, + state: Arc, undeclare_on_drop: bool, } -/// A [`Resolvable`] returned when undeclaring a [`LivelinessToken`](LivelinessToken). +/// A [`Resolvable`] returned when undeclaring a [`LivelinessToken`]. /// /// # Examples /// ``` @@ -332,9 +335,7 @@ pub struct LivelinessToken<'a> { /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[zenoh_macros::unstable] -pub struct LivelinessTokenUndeclaration<'a> { - token: LivelinessToken<'a>, -} +pub struct LivelinessTokenUndeclaration<'a>(LivelinessToken<'a>); #[zenoh_macros::unstable] impl Resolvable for LivelinessTokenUndeclaration<'_> { @@ -344,9 +345,7 @@ impl Resolvable for LivelinessTokenUndeclaration<'_> { #[zenoh_macros::unstable] impl Wait for LivelinessTokenUndeclaration<'_> { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.token.undeclare_on_drop = false; - self.token.session.undeclare_liveliness(self.token.state.id) + self.0.undeclare_impl() } } @@ -362,11 +361,7 @@ impl<'a> IntoFuture for LivelinessTokenUndeclaration<'a> { #[zenoh_macros::unstable] impl<'a> LivelinessToken<'a> { - /// Undeclare a [`LivelinessToken`]. - /// - /// LivelinessTokens are automatically closed when dropped, - /// but you may want to use this function to handle errors or - /// undeclare the LivelinessToken asynchronously. + /// Undeclare the [`LivelinessToken`]. /// /// # Examples /// ``` @@ -389,21 +384,21 @@ impl<'a> LivelinessToken<'a> { UndeclarableSealed::undeclare_inner(self, ()) } - /// Keep this liveliness token in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. + fn undeclare_impl(&mut self) -> ZResult<()> { self.undeclare_on_drop = false; + match self.session.upgrade() { + Some(session) => session.undeclare_liveliness(self.state.id), + None => Ok(()), + } } } #[zenoh_macros::unstable] -impl<'a> UndeclarableSealed<(), LivelinessTokenUndeclaration<'a>> for LivelinessToken<'a> { - fn undeclare_inner(self, _: ()) -> LivelinessTokenUndeclaration<'a> { - LivelinessTokenUndeclaration { token: self } +impl<'a> UndeclarableSealed<()> for LivelinessToken<'a> { + type Undeclaration = LivelinessTokenUndeclaration<'a>; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + LivelinessTokenUndeclaration(self) } } @@ -411,7 +406,9 @@ impl<'a> UndeclarableSealed<(), LivelinessTokenUndeclaration<'a>> for Liveliness impl Drop for LivelinessToken<'_> { fn drop(&mut self) { if self.undeclare_on_drop { - let _ = self.session.undeclare_liveliness(self.state.id); + if let Err(error) = self.undeclare_impl() { + error!(error); + } } } } @@ -578,11 +575,13 @@ where session .declare_liveliness_subscriber_inner(&key_expr, Locality::default(), callback) .map(|sub_state| Subscriber { - subscriber: SubscriberInner { - session, + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: session.into(), state: sub_state, kind: SubscriberKind::LivelinessSubscriber, - undeclare_on_drop: true, + undeclare_on_drop: size_of::() > 0, }, handler, }) diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index 02cfb406c9..4371255ac4 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -21,6 +21,7 @@ use std::{ }; use futures::Sink; +use tracing::error; use zenoh_core::{zread, Resolvable, Resolve, Wait}; use zenoh_protocol::{ core::{CongestionControl, Reliability}, @@ -78,7 +79,7 @@ impl fmt::Debug for PublisherState { #[derive(Clone)] pub enum PublisherRef<'a> { Borrow(&'a Publisher<'a>), - Shared(std::sync::Arc>), + Shared(Arc>), } #[zenoh_macros::unstable] @@ -349,7 +350,7 @@ impl<'a> Publisher<'a> { } } - /// Undeclares the [`Publisher`], informing the network that it needn't optimize publications for its key expression anymore. + /// Undeclare the [`Publisher`], informing the network that it needn't optimize publications for its key expression anymore. /// /// # Examples /// ``` @@ -366,13 +367,16 @@ impl<'a> Publisher<'a> { UndeclarableSealed::undeclare_inner(self, ()) } - #[cfg(feature = "unstable")] - fn undeclare_matching_listeners(&self) -> ZResult<()> { - let ids: Vec = zlock!(self.matching_listeners).drain().collect(); - for id in ids { - self.session.undeclare_matches_listener_inner(id)? + fn undeclare_impl(&mut self) -> ZResult<()> { + self.undeclare_on_drop = false; + #[cfg(feature = "unstable")] + { + let ids: Vec = zlock!(self.matching_listeners).drain().collect(); + for id in ids { + self.session.undeclare_matches_listener_inner(id)? + } } - Ok(()) + self.session.undeclare_publisher_inner(self.id) } } @@ -464,9 +468,11 @@ impl PublisherDeclarations for std::sync::Arc> { } } -impl<'a> UndeclarableSealed<(), PublisherUndeclaration<'a>> for Publisher<'a> { - fn undeclare_inner(self, _: ()) -> PublisherUndeclaration<'a> { - PublisherUndeclaration { publisher: self } +impl<'a> UndeclarableSealed<()> for Publisher<'a> { + type Undeclaration = PublisherUndeclaration<'a>; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + PublisherUndeclaration(self) } } @@ -484,9 +490,7 @@ impl<'a> UndeclarableSealed<(), PublisherUndeclaration<'a>> for Publisher<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct PublisherUndeclaration<'a> { - publisher: Publisher<'a>, -} +pub struct PublisherUndeclaration<'a>(Publisher<'a>); impl Resolvable for PublisherUndeclaration<'_> { type To = ZResult<()>; @@ -494,13 +498,7 @@ impl Resolvable for PublisherUndeclaration<'_> { impl Wait for PublisherUndeclaration<'_> { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.publisher.undeclare_on_drop = false; - #[cfg(feature = "unstable")] - self.publisher.undeclare_matching_listeners()?; - self.publisher - .session - .undeclare_publisher_inner(self.publisher.id) + self.0.undeclare_impl() } } @@ -516,9 +514,9 @@ impl IntoFuture for PublisherUndeclaration<'_> { impl Drop for Publisher<'_> { fn drop(&mut self) { if self.undeclare_on_drop { - #[cfg(feature = "unstable")] - let _ = self.undeclare_matching_listeners(); - let _ = self.session.undeclare_publisher_inner(self.id); + if let Err(error) = self.undeclare_impl() { + error!(error); + } } } } @@ -933,7 +931,6 @@ where listener: MatchingListenerInner { publisher: self.publisher, state, - undeclare_on_drop: true, }, receiver, }) @@ -958,7 +955,7 @@ where #[zenoh_macros::unstable] pub(crate) struct MatchingListenerState { pub(crate) id: Id, - pub(crate) current: std::sync::Mutex, + pub(crate) current: Mutex, pub(crate) key_expr: KeyExpr<'static>, pub(crate) destination: Locality, pub(crate) callback: Callback<'static, MatchingStatus>, @@ -977,8 +974,7 @@ impl std::fmt::Debug for MatchingListenerState { #[zenoh_macros::unstable] pub(crate) struct MatchingListenerInner<'a> { pub(crate) publisher: PublisherRef<'a>, - pub(crate) state: std::sync::Arc, - undeclare_on_drop: bool, + pub(crate) state: Arc, } #[zenoh_macros::unstable] @@ -990,8 +986,10 @@ impl<'a> MatchingListenerInner<'a> { } #[zenoh_macros::unstable] -impl<'a> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingListenerInner<'a> { - fn undeclare_inner(self, _: ()) -> MatchingListenerUndeclaration<'a> { +impl<'a> UndeclarableSealed<()> for MatchingListenerInner<'a> { + type Undeclaration = MatchingListenerUndeclaration<'a>; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { MatchingListenerUndeclaration { subscriber: self } } } @@ -999,6 +997,9 @@ impl<'a> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingL /// A listener that sends notifications when the [`MatchingStatus`] of a /// publisher changes. /// +/// Matching litsteners run in background until the publisher is undeclared. +/// They can be manually undeclared, but will not be undeclared on drop. +/// /// # Examples /// ```no_run /// # #[tokio::main] @@ -1025,10 +1026,7 @@ pub struct MatchingListener<'a, Receiver> { #[zenoh_macros::unstable] impl<'a, Receiver> MatchingListener<'a, Receiver> { - /// Close a [`MatchingListener`]. - /// - /// MatchingListeners are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the MatchingListener asynchronously. + /// Undeclare the [`MatchingListener`]. /// /// # Examples /// ``` @@ -1046,19 +1044,13 @@ impl<'a, Receiver> MatchingListener<'a, Receiver> { pub fn undeclare(self) -> MatchingListenerUndeclaration<'a> { self.listener.undeclare() } - - /// Make the matching listener run in background, until the publisher is undeclared. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // The matching listener will be undeclared as part of publisher undeclaration. - self.listener.undeclare_on_drop = false; - } } #[zenoh_macros::unstable] -impl<'a, T> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingListener<'a, T> { - fn undeclare_inner(self, _: ()) -> MatchingListenerUndeclaration<'a> { +impl<'a, T> UndeclarableSealed<()> for MatchingListener<'a, T> { + type Undeclaration = MatchingListenerUndeclaration<'a>; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { UndeclarableSealed::undeclare_inner(self.listener, ()) } } @@ -1090,9 +1082,7 @@ impl Resolvable for MatchingListenerUndeclaration<'_> { #[zenoh_macros::unstable] impl Wait for MatchingListenerUndeclaration<'_> { - fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.subscriber.undeclare_on_drop = false; + fn wait(self) -> ::To { zlock!(self.subscriber.publisher.matching_listeners).remove(&self.subscriber.state.id); self.subscriber .publisher @@ -1111,19 +1101,6 @@ impl IntoFuture for MatchingListenerUndeclaration<'_> { } } -#[zenoh_macros::unstable] -impl Drop for MatchingListenerInner<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - zlock!(self.publisher.matching_listeners).remove(&self.state.id); - let _ = self - .publisher - .session - .undeclare_matches_listener_inner(self.state.id); - } - } -} - #[cfg(test)] mod tests { use zenoh_config::Config; diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 61ae0093ea..d39b2411f5 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -14,10 +14,12 @@ use std::{ fmt, future::{IntoFuture, Ready}, + mem::size_of, ops::{Deref, DerefMut}, sync::Arc, }; +use tracing::error; use uhlc::Timestamp; use zenoh_core::{Resolvable, Resolve, Wait}; use zenoh_protocol::{ @@ -28,30 +30,32 @@ use zenoh_protocol::{ use zenoh_result::ZResult; #[zenoh_macros::unstable] use { - super::{query::ReplyKeyExpr, sample::SourceInfo}, - zenoh_config::wrappers::EntityGlobalId, + crate::api::{query::ReplyKeyExpr, sample::SourceInfo}, + zenoh_config::wrappers::{EntityGlobalId, ZenohId}, zenoh_protocol::core::EntityGlobalIdProto, }; #[zenoh_macros::unstable] -use super::selector::ZenohParameters; -use super::{ - builders::sample::{ - EncodingBuilderTrait, QoSBuilderTrait, SampleBuilder, SampleBuilderTrait, - TimestampBuilderTrait, +use crate::api::selector::ZenohParameters; +use crate::{ + api::{ + builders::sample::{ + EncodingBuilderTrait, QoSBuilderTrait, SampleBuilder, SampleBuilderTrait, + TimestampBuilderTrait, + }, + bytes::{OptionZBytes, ZBytes}, + encoding::Encoding, + handlers::{locked, DefaultHandler, IntoHandler}, + key_expr::KeyExpr, + publisher::Priority, + sample::{Locality, QoSBuilder, Sample, SampleKind}, + selector::Selector, + session::{SessionRef, UndeclarableSealed, WeakSessionRef}, + value::Value, + Id, }, - bytes::{OptionZBytes, ZBytes}, - encoding::Encoding, - handlers::{locked, DefaultHandler, IntoHandler}, - key_expr::KeyExpr, - publisher::Priority, - sample::{Locality, QoSBuilder, Sample, SampleKind}, - selector::Selector, - session::{SessionRef, UndeclarableSealed}, - value::Value, - Id, + net::primitives::Primitives, }; -use crate::net::primitives::Primitives; pub(crate) struct QueryInner { pub(crate) key_expr: KeyExpr<'static>, @@ -534,43 +538,13 @@ impl fmt::Debug for QueryableState { } } -/// An entity able to reply to queries through a callback. -/// -/// CallbackQueryables can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_queryable`](crate::Session::declare_queryable) function -/// and the [`callback`](QueryableBuilder::callback) function -/// of the resulting builder. -/// -/// Queryables are automatically undeclared when dropped. -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use futures::prelude::*; -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); -/// let queryable = session.declare_queryable("key/expression").await.unwrap(); -/// while let Ok(query) = queryable.recv_async().await { -/// println!(">> Handling query '{}'", query.selector()); -/// query.reply("key/expression", "value") -/// .await -/// .unwrap(); -/// } -/// # } -/// ``` #[derive(Debug)] -pub(crate) struct CallbackQueryable<'a> { - pub(crate) session: SessionRef<'a>, +pub(crate) struct QueryableInner<'a> { + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: WeakSessionRef<'a>, pub(crate) state: Arc, - undeclare_on_drop: bool, -} - -impl<'a> UndeclarableSealed<(), QueryableUndeclaration<'a>> for CallbackQueryable<'a> { - fn undeclare_inner(self, _: ()) -> QueryableUndeclaration<'a> { - QueryableUndeclaration { queryable: self } - } + pub(crate) undeclare_on_drop: bool, } /// A [`Resolvable`] returned when undeclaring a queryable. @@ -587,25 +561,19 @@ impl<'a> UndeclarableSealed<(), QueryableUndeclaration<'a>> for CallbackQueryabl /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct QueryableUndeclaration<'a> { - queryable: CallbackQueryable<'a>, -} +pub struct QueryableUndeclaration<'a, Handler>(Queryable<'a, Handler>); -impl Resolvable for QueryableUndeclaration<'_> { +impl Resolvable for QueryableUndeclaration<'_, Handler> { type To = ZResult<()>; } -impl Wait for QueryableUndeclaration<'_> { +impl Wait for QueryableUndeclaration<'_, Handler> { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.queryable.undeclare_on_drop = false; - self.queryable - .session - .close_queryable(self.queryable.state.id) + self.0.undeclare_impl() } } -impl<'a> IntoFuture for QueryableUndeclaration<'a> { +impl IntoFuture for QueryableUndeclaration<'_, Handler> { type Output = ::To; type IntoFuture = Ready<::To>; @@ -614,14 +582,6 @@ impl<'a> IntoFuture for QueryableUndeclaration<'a> { } } -impl Drop for CallbackQueryable<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - let _ = self.session.close_queryable(self.state.id); - } - } -} - /// A builder for initializing a [`Queryable`]. /// /// # Examples @@ -778,9 +738,37 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// and the [`with`](QueryableBuilder::with) function /// of the resulting builder. /// -/// Queryables are automatically undeclared when dropped. +/// Callback queryables will run in background until the session is closed, +/// or until it is undeclared. +/// On the other hand, queryables with a handler are automatically undeclared when dropped. /// /// # Examples +/// +/// Using callback: +/// ```no_run +/// # #[tokio::main] +/// # async fn main() { +/// use futures::prelude::*; +/// use zenoh::prelude::*; +/// +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); +/// let (tx, rx) = flume::bounded(32); +/// session +/// .declare_queryable("key/expression") +/// .callback(|query| tx.send(query).unwrap()) +/// .await +/// .unwrap(); +/// // queryable run in background until the session is closed +/// tokio::spawn(async move { +/// while let Ok(query) = rx.recv().await { +/// println!(">> Handling query '{}'", query.selector()); +/// query.reply("key/expression", "value").await.unwrap(); +/// } +/// }); +/// # } +/// ``` +/// +/// Using channel handler: /// ```no_run /// # #[tokio::main] /// # async fn main() { @@ -798,12 +786,13 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// .await /// .unwrap(); /// } +/// // queryable is undeclared at the end of the scope /// # } /// ``` #[non_exhaustive] #[derive(Debug)] pub struct Queryable<'a, Handler> { - pub(crate) queryable: CallbackQueryable<'a>, + pub(crate) inner: QueryableInner<'a>, pub(crate) handler: Handler, } @@ -826,8 +815,8 @@ impl<'a, Handler> Queryable<'a, Handler> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.queryable.session.zid().into(), - eid: self.queryable.state.id, + zid: self.inner.session_id.into(), + eid: self.inner.state.id, } .into() } @@ -846,25 +835,53 @@ impl<'a, Handler> Queryable<'a, Handler> { &mut self.handler } + /// Undeclare the [`Queryable`]. + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// use zenoh::prelude::*; + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let queryable = session.declare_queryable("key/expression") + /// .await + /// .unwrap(); + /// queryable.undeclare().await.unwrap(); + /// # } + /// ``` #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> + 'a + where + Handler: Send + 'a, + { UndeclarableSealed::undeclare_inner(self, ()) } - /// Make the queryable run in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. - self.queryable.undeclare_on_drop = false; + fn undeclare_impl(&mut self) -> ZResult<()> { + self.inner.undeclare_on_drop = false; + match self.inner.session.upgrade() { + Some(session) => session.close_queryable(self.inner.state.id), + None => Ok(()), + } + } +} + +impl Drop for Queryable<'_, Handler> { + fn drop(&mut self) { + if self.inner.undeclare_on_drop { + if let Err(error) = self.undeclare_impl() { + error!(error); + } + } } } -impl<'a, T> UndeclarableSealed<(), QueryableUndeclaration<'a>> for Queryable<'a, T> { - fn undeclare_inner(self, _: ()) -> QueryableUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self.queryable, ()) +impl<'a, Handler: Send + 'a> UndeclarableSealed<()> for Queryable<'a, Handler> { + type Undeclaration = QueryableUndeclaration<'a, Handler>; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + QueryableUndeclaration(self) } } @@ -906,10 +923,12 @@ where callback, ) .map(|qable_state| Queryable { - queryable: CallbackQueryable { - session, + inner: QueryableInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: session.into(), state: qable_state, - undeclare_on_drop: true, + undeclare_on_drop: size_of::() > 0, }, handler: receiver, }) diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index 26704d378a..b6efb5946f 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -19,7 +19,7 @@ use std::{ ops::Deref, sync::{ atomic::{AtomicU16, Ordering}, - Arc, RwLock, + Arc, RwLock, Weak, }, time::{Duration, SystemTime, UNIX_EPOCH}, }; @@ -452,19 +452,43 @@ impl fmt::Debug for SessionRef<'_> { } } -pub(crate) trait UndeclarableSealed> -where - O: Resolve + Send, -{ - fn undeclare_inner(self, session: S) -> O; +#[derive(Debug, Clone)] +pub(crate) enum WeakSessionRef<'a> { + Borrow(&'a Session), + Shared(Weak), } -impl<'a, O, T, G> UndeclarableSealed<&'a Session, O, T> for G +impl<'a> WeakSessionRef<'a> { + pub(crate) fn upgrade(&self) -> Option> { + match self { + Self::Borrow(s) => Some(SessionRef::Borrow(s)), + Self::Shared(s) => s.upgrade().map(SessionRef::Shared), + } + } +} + +impl<'a> From> for WeakSessionRef<'a> { + fn from(value: SessionRef<'a>) -> Self { + match value { + SessionRef::Borrow(s) => Self::Borrow(s), + SessionRef::Shared(s) => Self::Shared(Arc::downgrade(&s)), + } + } +} + +/// A trait implemented by types that can be undeclared. +pub trait UndeclarableSealed { + type Undeclaration: Resolve> + Send; + fn undeclare_inner(self, session: S) -> Self::Undeclaration; +} + +impl<'a, T> UndeclarableSealed<&'a Session> for T where - O: Resolve + Send, - G: UndeclarableSealed<(), O, T>, + T: UndeclarableSealed<()>, { - fn undeclare_inner(self, _: &'a Session) -> O { + type Undeclaration = >::Undeclaration; + + fn undeclare_inner(self, _session: &'a Session) -> Self::Undeclaration { self.undeclare_inner(()) } } @@ -473,18 +497,9 @@ where // care about the `private_bounds` lint in this particular case. #[allow(private_bounds)] /// A trait implemented by types that can be undeclared. -pub trait Undeclarable: UndeclarableSealed -where - O: Resolve + Send, -{ -} +pub trait Undeclarable: UndeclarableSealed {} -impl Undeclarable for U -where - O: Resolve + Send, - U: UndeclarableSealed, -{ -} +impl Undeclarable for T where T: UndeclarableSealed {} /// A zenoh session. /// @@ -637,10 +652,9 @@ impl Session { }) } - pub fn undeclare<'a, T, O>(&'a self, decl: T) -> O + pub fn undeclare<'a, T>(&'a self, decl: T) -> impl Resolve> + 'a where - O: Resolve>, - T: Undeclarable<&'a Self, O, ZResult<()>>, + T: Undeclarable<&'a Session> + 'a, { UndeclarableSealed::undeclare_inner(decl, self) } @@ -771,13 +785,6 @@ impl Session { >>::Error: Into, { let key_expr: ZResult = key_expr.try_into().map_err(Into::into); - self._declare_keyexpr(key_expr) - } - - fn _declare_keyexpr<'a, 'b: 'a>( - &'a self, - key_expr: ZResult>, - ) -> impl Resolve>> + 'a { let sid = self.id; ResolveClosure::new(move || { let key_expr: KeyExpr = key_expr?; diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index 0e82a20331..abeb36aa28 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -15,21 +15,26 @@ use std::{ fmt, future::{IntoFuture, Ready}, + mem::size_of, ops::{Deref, DerefMut}, sync::Arc, }; +use tracing::error; use zenoh_core::{Resolvable, Wait}; use zenoh_protocol::network::declare::subscriber::ext::SubscriberInfo; use zenoh_result::ZResult; #[cfg(feature = "unstable")] -use {zenoh_config::wrappers::EntityGlobalId, zenoh_protocol::core::EntityGlobalIdProto}; +use { + zenoh_config::wrappers::{EntityGlobalId, ZenohId}, + zenoh_protocol::core::EntityGlobalIdProto, +}; -use super::{ +use crate::api::{ handlers::{locked, Callback, DefaultHandler, IntoHandler}, key_expr::KeyExpr, sample::{Locality, Sample}, - session::{SessionRef, UndeclarableSealed}, + session::{SessionRef, UndeclarableSealed, WeakSessionRef}, Id, }; #[cfg(feature = "unstable")] @@ -52,71 +57,16 @@ impl fmt::Debug for SubscriberState { } } -/// A subscriber that provides data through a callback. -/// -/// CallbackSubscribers can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_subscriber`](crate::SessionDeclarations::declare_subscriber) function -/// and the [`callback`](SubscriberBuilder::callback) function -/// of the resulting builder. -/// -/// Subscribers are automatically undeclared when dropped. -/// -/// # Examples -/// ``` -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); -/// let subscriber = session -/// .declare_subscriber("key/expression") -/// .callback(|sample| { println!("Received: {} {:?}", sample.key_expr(), sample.payload()) }) -/// .await -/// .unwrap(); -/// # } -/// ``` #[derive(Debug)] pub(crate) struct SubscriberInner<'a> { - pub(crate) session: SessionRef<'a>, + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: WeakSessionRef<'a>, pub(crate) state: Arc, pub(crate) kind: SubscriberKind, pub(crate) undeclare_on_drop: bool, } -impl<'a> SubscriberInner<'a> { - /// Close a [`CallbackSubscriber`](CallbackSubscriber). - /// - /// `CallbackSubscribers` are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the `CallbackSubscriber` asynchronously. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::{prelude::*, sample::Sample}; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); - /// # fn data_handler(_sample: Sample) { }; - /// let subscriber = session - /// .declare_subscriber("key/expression") - /// .callback(data_handler) - /// .await - /// .unwrap(); - /// subscriber.undeclare().await.unwrap(); - /// # } - /// ``` - #[inline] - pub fn undeclare(self) -> SubscriberUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self, ()) - } -} - -impl<'a> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for SubscriberInner<'a> { - fn undeclare_inner(self, _: ()) -> SubscriberUndeclaration<'a> { - SubscriberUndeclaration { subscriber: self } - } -} - /// A [`Resolvable`] returned when undeclaring a subscriber. /// /// # Examples @@ -134,25 +84,19 @@ impl<'a> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for SubscriberInner /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct SubscriberUndeclaration<'a> { - subscriber: SubscriberInner<'a>, -} +pub struct SubscriberUndeclaration<'a, Handler>(Subscriber<'a, Handler>); -impl Resolvable for SubscriberUndeclaration<'_> { +impl Resolvable for SubscriberUndeclaration<'_, Handler> { type To = ZResult<()>; } -impl Wait for SubscriberUndeclaration<'_> { +impl Wait for SubscriberUndeclaration<'_, Handler> { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.subscriber.undeclare_on_drop = false; - self.subscriber - .session - .undeclare_subscriber_inner(self.subscriber.state.id, self.subscriber.kind) + self.0.undeclare_impl() } } -impl IntoFuture for SubscriberUndeclaration<'_> { +impl IntoFuture for SubscriberUndeclaration<'_, Handler> { type Output = ::To; type IntoFuture = Ready<::To>; @@ -161,16 +105,6 @@ impl IntoFuture for SubscriberUndeclaration<'_> { } } -impl Drop for SubscriberInner<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - let _ = self - .session - .undeclare_subscriber_inner(self.state.id, self.kind); - } - } -} - /// A builder for initializing a [`FlumeSubscriber`]. /// /// # Examples @@ -394,11 +328,13 @@ where &SubscriberInfo::default(), ) .map(|sub_state| Subscriber { - subscriber: SubscriberInner { - session, + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: session.into(), state: sub_state, kind: SubscriberKind::Subscriber, - undeclare_on_drop: true, + undeclare_on_drop: size_of::() > 0, }, handler: receiver, }) @@ -425,9 +361,29 @@ where /// and the [`with`](SubscriberBuilder::with) function /// of the resulting builder. /// -/// Subscribers are automatically undeclared when dropped. +/// Callback subscribers will run in background until the session is closed, +/// or until it is undeclared. +/// On the other hand, subscribers with a handler are automatically undeclared when dropped. /// /// # Examples +/// +/// Using callback: +/// ```no_run +/// # #[tokio::main] +/// # async fn main() { +/// use zenoh::prelude::*; +/// +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); +/// session +/// .declare_subscriber("key/expression") +/// .callback(|sample| { println!("Received: {} {:?}", sample.key_expr(), sample.payload()) }) +/// .await +/// .unwrap(); +/// // subscriber run in background until the session is closed +/// # } +/// ``` +/// +/// Using channel handler: /// ```no_run /// # #[tokio::main] /// # async fn main() { @@ -442,12 +398,13 @@ where /// while let Ok(sample) = subscriber.recv_async().await { /// println!("Received: {} {:?}", sample.key_expr(), sample.payload()); /// } +/// // subscriber is undeclared at the end of the scope /// # } /// ``` #[non_exhaustive] #[derive(Debug)] pub struct Subscriber<'a, Handler> { - pub(crate) subscriber: SubscriberInner<'a>, + pub(crate) inner: SubscriberInner<'a>, pub(crate) handler: Handler, } @@ -470,15 +427,15 @@ impl<'a, Handler> Subscriber<'a, Handler> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.subscriber.session.zid().into(), - eid: self.subscriber.state.id, + zid: self.inner.session_id.into(), + eid: self.inner.state.id, } .into() } /// Returns the [`KeyExpr`] this Subscriber subscribes to. pub fn key_expr(&self) -> &KeyExpr<'static> { - &self.subscriber.state.key_expr + &self.inner.state.key_expr } /// Returns a reference to this subscriber's handler. @@ -495,10 +452,7 @@ impl<'a, Handler> Subscriber<'a, Handler> { &mut self.handler } - /// Close a [`Subscriber`]. - /// - /// Subscribers are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the Subscriber asynchronously. + /// Undeclare the [`Subscriber`]. /// /// # Examples /// ``` @@ -514,24 +468,39 @@ impl<'a, Handler> Subscriber<'a, Handler> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> SubscriberUndeclaration<'a> { - self.subscriber.undeclare() + pub fn undeclare(self) -> SubscriberUndeclaration<'a, Handler> + where + Handler: Send + 'a, + { + self.undeclare_inner(()) } - /// Make the subscriber run in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. - self.subscriber.undeclare_on_drop = false; + fn undeclare_impl(&mut self) -> ZResult<()> { + self.inner.undeclare_on_drop = false; + match self.inner.session.upgrade() { + Some(session) => { + session.undeclare_subscriber_inner(self.inner.state.id, self.inner.kind) + } + None => Ok(()), + } } } -impl<'a, T> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for Subscriber<'a, T> { - fn undeclare_inner(self, _: ()) -> SubscriberUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self.subscriber, ()) +impl Drop for Subscriber<'_, Handler> { + fn drop(&mut self) { + if self.inner.undeclare_on_drop { + if let Err(error) = self.undeclare_impl() { + error!(error); + } + } + } +} + +impl<'a, Handler: Send + 'a> UndeclarableSealed<()> for Subscriber<'a, Handler> { + type Undeclaration = SubscriberUndeclaration<'a, Handler>; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + SubscriberUndeclaration(self) } } diff --git a/zenoh/src/lib.rs b/zenoh/src/lib.rs index 0190acc319..1b563bb4e4 100644 --- a/zenoh/src/lib.rs +++ b/zenoh/src/lib.rs @@ -191,13 +191,15 @@ pub mod session { pub use zenoh_config::wrappers::{EntityGlobalId, ZenohId}; pub use zenoh_protocol::core::EntityId; + #[zenoh_macros::unstable] + pub use crate::api::session::SessionRef; #[zenoh_macros::internal] pub use crate::api::session::{init, InitBuilder}; pub use crate::api::{ builders::publisher::{SessionDeleteBuilder, SessionPutBuilder}, info::{PeersZenohIdBuilder, RoutersZenohIdBuilder, SessionInfo, ZenohIdBuilder}, query::SessionGetBuilder, - session::{open, OpenBuilder, Session, SessionDeclarations, SessionRef, Undeclarable}, + session::{open, OpenBuilder, Session, SessionDeclarations, Undeclarable}, }; } From 82e7b16808c97828deffa6931d1b857e4d099a33 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 28 Aug 2024 07:51:27 +0200 Subject: [PATCH 23/33] fix: fix example --- zenoh/src/api/queryable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index d39b2411f5..bf8c482537 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -760,7 +760,7 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// .unwrap(); /// // queryable run in background until the session is closed /// tokio::spawn(async move { -/// while let Ok(query) = rx.recv().await { +/// while let Ok(query) = rx.recv_async().await { /// println!(">> Handling query '{}'", query.selector()); /// query.reply("key/expression", "value").await.unwrap(); /// } From 15fff73a9fc65d8436ac4a2ed8ef5b4524e659a1 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 28 Aug 2024 08:24:54 +0200 Subject: [PATCH 24/33] fix: fix example --- zenoh/src/api/queryable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index bf8c482537..163d32c011 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -755,7 +755,7 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// let (tx, rx) = flume::bounded(32); /// session /// .declare_queryable("key/expression") -/// .callback(|query| tx.send(query).unwrap()) +/// .callback(move |query| tx.send(query).unwrap()) /// .await /// .unwrap(); /// // queryable run in background until the session is closed From a1ff4a632060ef661fa562f329ede2d90a520048 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Mon, 2 Sep 2024 09:33:03 +0200 Subject: [PATCH 25/33] fix: add missing comment about ZST trick --- zenoh/src/api/liveliness.rs | 2 ++ zenoh/src/api/publisher.rs | 1 + zenoh/src/api/queryable.rs | 3 +++ zenoh/src/api/subscriber.rs | 3 +++ 4 files changed, 9 insertions(+) diff --git a/zenoh/src/api/liveliness.rs b/zenoh/src/api/liveliness.rs index bb068b4e52..10788f39e9 100644 --- a/zenoh/src/api/liveliness.rs +++ b/zenoh/src/api/liveliness.rs @@ -385,6 +385,7 @@ impl<'a> LivelinessToken<'a> { } fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic self.undeclare_on_drop = false; match self.session.upgrade() { Some(session) => session.undeclare_liveliness(self.state.id), @@ -581,6 +582,7 @@ where session: session.into(), state: sub_state, kind: SubscriberKind::LivelinessSubscriber, + // `size_of::() == 0` means callback-only subscriber undeclare_on_drop: size_of::() > 0, }, handler, diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index 4371255ac4..0661ad3dec 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -368,6 +368,7 @@ impl<'a> Publisher<'a> { } fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic self.undeclare_on_drop = false; #[cfg(feature = "unstable")] { diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 163d32c011..89938f213b 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -544,6 +544,7 @@ pub(crate) struct QueryableInner<'a> { pub(crate) session_id: ZenohId, pub(crate) session: WeakSessionRef<'a>, pub(crate) state: Arc, + // Queryable is undeclared on drop unless its handler is a ZST, i.e. it is callback-only pub(crate) undeclare_on_drop: bool, } @@ -859,6 +860,7 @@ impl<'a, Handler> Queryable<'a, Handler> { } fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic self.inner.undeclare_on_drop = false; match self.inner.session.upgrade() { Some(session) => session.close_queryable(self.inner.state.id), @@ -928,6 +930,7 @@ where session_id: session.zid(), session: session.into(), state: qable_state, + // `size_of::() == 0` means callback-only queryable undeclare_on_drop: size_of::() > 0, }, handler: receiver, diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index abeb36aa28..7c62e0502d 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -64,6 +64,7 @@ pub(crate) struct SubscriberInner<'a> { pub(crate) session: WeakSessionRef<'a>, pub(crate) state: Arc, pub(crate) kind: SubscriberKind, + // Subscriber is undeclared on drop unless its handler is a ZST, i.e. it is callback-only pub(crate) undeclare_on_drop: bool, } @@ -334,6 +335,7 @@ where session: session.into(), state: sub_state, kind: SubscriberKind::Subscriber, + // `size_of::() == 0` means callback-only subscriber undeclare_on_drop: size_of::() > 0, }, handler: receiver, @@ -476,6 +478,7 @@ impl<'a, Handler> Subscriber<'a, Handler> { } fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic self.inner.undeclare_on_drop = false; match self.inner.session.upgrade() { Some(session) => { From 0d4423b5c209c2b9ddce4510ae4da24907230946 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Mon, 2 Sep 2024 16:19:08 +0200 Subject: [PATCH 26/33] Update zenoh/src/api/key_expr.rs Co-authored-by: Luca Cominardi --- zenoh/src/api/key_expr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/zenoh/src/api/key_expr.rs b/zenoh/src/api/key_expr.rs index bde77f5d32..8b11472dfb 100644 --- a/zenoh/src/api/key_expr.rs +++ b/zenoh/src/api/key_expr.rs @@ -551,6 +551,7 @@ impl<'a> KeyExpr<'a> { impl<'a> UndeclarableSealed<&'a Session> for KeyExpr<'a> { type Undeclaration = KeyExprUndeclaration<'a>; + fn undeclare_inner(self, session: &'a Session) -> Self::Undeclaration { KeyExprUndeclaration { session, From 150c497f989e94f92b355e2797af7006ed7d2de5 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Mon, 2 Sep 2024 17:24:01 +0200 Subject: [PATCH 27/33] fix: formatting --- zenoh/src/api/key_expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zenoh/src/api/key_expr.rs b/zenoh/src/api/key_expr.rs index 8b11472dfb..0f0d13a69c 100644 --- a/zenoh/src/api/key_expr.rs +++ b/zenoh/src/api/key_expr.rs @@ -551,7 +551,7 @@ impl<'a> KeyExpr<'a> { impl<'a> UndeclarableSealed<&'a Session> for KeyExpr<'a> { type Undeclaration = KeyExprUndeclaration<'a>; - + fn undeclare_inner(self, session: &'a Session) -> Self::Undeclaration { KeyExprUndeclaration { session, From baa242600e01dc3c49259087b1c4ae1d8404a81f Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Tue, 3 Sep 2024 11:27:16 +0200 Subject: [PATCH 28/33] fix: don't use `Weak` when undeclared on drop --- zenoh/src/api/liveliness.rs | 34 +++++++++++++++++++--------------- zenoh/src/api/queryable.rs | 27 +++++++++++++++------------ zenoh/src/api/session.rs | 27 ++++++++++++++------------- zenoh/src/api/subscriber.rs | 29 ++++++++++++++++------------- 4 files changed, 64 insertions(+), 53 deletions(-) diff --git a/zenoh/src/api/liveliness.rs b/zenoh/src/api/liveliness.rs index 10788f39e9..f22de66b02 100644 --- a/zenoh/src/api/liveliness.rs +++ b/zenoh/src/api/liveliness.rs @@ -33,7 +33,7 @@ use super::{ subscriber::{Subscriber, SubscriberInner}, Id, }; -use crate::api::session::WeakSessionRef; +use crate::api::session::MaybeWeakSessionRef; /// A structure with functions to declare a /// [`LivelinessToken`](LivelinessToken), query @@ -254,12 +254,13 @@ impl Wait for LivelinessTokenBuilder<'_, '_> { fn wait(self) -> ::To { let session = self.session; let key_expr = self.key_expr?.into_owned(); + let undeclare_on_drop = true; session .declare_liveliness_inner(&key_expr) .map(|tok_state| LivelinessToken { - session: session.into(), + session: MaybeWeakSessionRef::new(session, !undeclare_on_drop), state: tok_state, - undeclare_on_drop: true, + undeclare_on_drop, }) } } @@ -310,7 +311,7 @@ pub(crate) struct LivelinessTokenState { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessToken<'a> { - session: WeakSessionRef<'a>, + session: MaybeWeakSessionRef<'a>, state: Arc, undeclare_on_drop: bool, } @@ -573,19 +574,22 @@ where let key_expr = self.key_expr?; let session = self.session; let (callback, handler) = self.handler.into_handler(); + let undeclare_on_drop = size_of::() > 0; session .declare_liveliness_subscriber_inner(&key_expr, Locality::default(), callback) - .map(|sub_state| Subscriber { - inner: SubscriberInner { - #[cfg(feature = "unstable")] - session_id: session.zid(), - session: session.into(), - state: sub_state, - kind: SubscriberKind::LivelinessSubscriber, - // `size_of::() == 0` means callback-only subscriber - undeclare_on_drop: size_of::() > 0, - }, - handler, + .map(|sub_state| { + Subscriber { + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: MaybeWeakSessionRef::new(session, !undeclare_on_drop), + state: sub_state, + kind: SubscriberKind::LivelinessSubscriber, + // `size_of::() == 0` means callback-only subscriber + undeclare_on_drop, + }, + handler, + } }) } } diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 89938f213b..56b26fa36e 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -50,7 +50,7 @@ use crate::{ publisher::Priority, sample::{Locality, QoSBuilder, Sample, SampleKind}, selector::Selector, - session::{SessionRef, UndeclarableSealed, WeakSessionRef}, + session::{MaybeWeakSessionRef, SessionRef, UndeclarableSealed}, value::Value, Id, }, @@ -542,7 +542,7 @@ impl fmt::Debug for QueryableState { pub(crate) struct QueryableInner<'a> { #[cfg(feature = "unstable")] pub(crate) session_id: ZenohId, - pub(crate) session: WeakSessionRef<'a>, + pub(crate) session: MaybeWeakSessionRef<'a>, pub(crate) state: Arc, // Queryable is undeclared on drop unless its handler is a ZST, i.e. it is callback-only pub(crate) undeclare_on_drop: bool, @@ -917,6 +917,7 @@ where fn wait(self) -> ::To { let session = self.session; let (callback, receiver) = self.handler.into_handler(); + let undeclare_on_drop = size_of::() > 0; session .declare_queryable_inner( &self.key_expr?.to_wire(&session), @@ -924,16 +925,18 @@ where self.origin, callback, ) - .map(|qable_state| Queryable { - inner: QueryableInner { - #[cfg(feature = "unstable")] - session_id: session.zid(), - session: session.into(), - state: qable_state, - // `size_of::() == 0` means callback-only queryable - undeclare_on_drop: size_of::() > 0, - }, - handler: receiver, + .map(|qable_state| { + Queryable { + inner: QueryableInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: MaybeWeakSessionRef::new(session, !undeclare_on_drop), + state: qable_state, + // `size_of::() == 0` means callback-only queryable + undeclare_on_drop, + }, + handler: receiver, + } }) } } diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index b6efb5946f..231ab85d6d 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -453,25 +453,26 @@ impl fmt::Debug for SessionRef<'_> { } #[derive(Debug, Clone)] -pub(crate) enum WeakSessionRef<'a> { +pub(crate) enum MaybeWeakSessionRef<'a> { Borrow(&'a Session), - Shared(Weak), + Arc(Arc), + Weak(Weak), } -impl<'a> WeakSessionRef<'a> { - pub(crate) fn upgrade(&self) -> Option> { - match self { - Self::Borrow(s) => Some(SessionRef::Borrow(s)), - Self::Shared(s) => s.upgrade().map(SessionRef::Shared), +impl<'a> MaybeWeakSessionRef<'a> { + pub(crate) fn new(session: SessionRef<'a>, downgrade: bool) -> Self { + match session { + SessionRef::Borrow(s) => Self::Borrow(s), + SessionRef::Shared(s) if downgrade => Self::Weak(Arc::downgrade(&s)), + SessionRef::Shared(s) => Self::Arc(s), } } -} -impl<'a> From> for WeakSessionRef<'a> { - fn from(value: SessionRef<'a>) -> Self { - match value { - SessionRef::Borrow(s) => Self::Borrow(s), - SessionRef::Shared(s) => Self::Shared(Arc::downgrade(&s)), + pub(crate) fn upgrade(&self) -> Option> { + match self { + Self::Borrow(s) => Some(SessionRef::Borrow(s)), + Self::Arc(s) => Some(SessionRef::Shared(s.clone())), + Self::Weak(s) => s.upgrade().map(SessionRef::Shared), } } } diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index 7c62e0502d..5bca8abcfa 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -34,7 +34,7 @@ use crate::api::{ handlers::{locked, Callback, DefaultHandler, IntoHandler}, key_expr::KeyExpr, sample::{Locality, Sample}, - session::{SessionRef, UndeclarableSealed, WeakSessionRef}, + session::{MaybeWeakSessionRef, SessionRef, UndeclarableSealed}, Id, }; #[cfg(feature = "unstable")] @@ -61,7 +61,7 @@ impl fmt::Debug for SubscriberState { pub(crate) struct SubscriberInner<'a> { #[cfg(feature = "unstable")] pub(crate) session_id: ZenohId, - pub(crate) session: WeakSessionRef<'a>, + pub(crate) session: MaybeWeakSessionRef<'a>, pub(crate) state: Arc, pub(crate) kind: SubscriberKind, // Subscriber is undeclared on drop unless its handler is a ZST, i.e. it is callback-only @@ -316,6 +316,7 @@ where let key_expr = self.key_expr?; let session = self.session; let (callback, receiver) = self.handler.into_handler(); + let undeclare_on_drop = size_of::() > 0; session .declare_subscriber_inner( &key_expr, @@ -328,17 +329,19 @@ where #[cfg(not(feature = "unstable"))] &SubscriberInfo::default(), ) - .map(|sub_state| Subscriber { - inner: SubscriberInner { - #[cfg(feature = "unstable")] - session_id: session.zid(), - session: session.into(), - state: sub_state, - kind: SubscriberKind::Subscriber, - // `size_of::() == 0` means callback-only subscriber - undeclare_on_drop: size_of::() > 0, - }, - handler: receiver, + .map(|sub_state| { + Subscriber { + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: MaybeWeakSessionRef::new(session, !undeclare_on_drop), + state: sub_state, + kind: SubscriberKind::Subscriber, + // `size_of::() == 0` means callback-only subscriber + undeclare_on_drop, + }, + handler: receiver, + } }) } } From 2c52a3c3530db593405c86b684e0fe117b66ba97 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Tue, 3 Sep 2024 05:52:25 +0200 Subject: [PATCH 29/33] feat!: make session an arc-like object The refactoring is quite deep, so this is the first (dirty) iteration which passes the tests. --- examples/examples/z_forward.rs | 2 +- examples/examples/z_get_liveliness.rs | 2 +- examples/examples/z_info.rs | 2 +- examples/examples/z_liveliness.rs | 2 +- examples/examples/z_pong.rs | 2 +- examples/examples/z_pull.rs | 2 +- examples/examples/z_queryable.rs | 2 +- examples/examples/z_queryable_shm.rs | 1 - examples/examples/z_storage.rs | 1 - examples/examples/z_sub.rs | 2 +- examples/examples/z_sub_liveliness.rs | 2 +- examples/examples/z_sub_shm.rs | 2 +- plugins/zenoh-plugin-example/src/lib.rs | 1 - .../zenoh-plugin-rest/examples/z_serve_sse.rs | 1 - plugins/zenoh-plugin-rest/src/lib.rs | 2 +- .../src/replica/mod.rs | 2 +- .../src/replica/storage.rs | 2 +- zenoh-ext/examples/examples/z_query_sub.rs | 2 +- zenoh-ext/src/publication_cache.rs | 25 +- zenoh-ext/src/querying_subscriber.rs | 24 +- zenoh-ext/src/session_ext.rs | 59 +- zenoh-ext/src/subscriber_ext.rs | 2 +- zenoh-ext/tests/liveliness.rs | 4 +- zenoh/src/api/admin.rs | 52 +- zenoh/src/api/builders/publisher.rs | 73 +- zenoh/src/api/info.rs | 29 +- zenoh/src/api/key_expr.rs | 14 +- zenoh/src/api/liveliness.rs | 81 +- zenoh/src/api/publisher.rs | 215 +--- zenoh/src/api/query.rs | 1 + zenoh/src/api/queryable.rs | 73 +- zenoh/src/api/session.rs | 1062 ++++++----------- zenoh/src/api/subscriber.rs | 85 +- zenoh/src/lib.rs | 5 +- zenoh/src/prelude.rs | 4 +- zenoh/tests/events.rs | 1 - zenoh/tests/liveliness.rs | 12 +- zenoh/tests/routing.rs | 6 +- 38 files changed, 673 insertions(+), 1186 deletions(-) diff --git a/examples/examples/z_forward.rs b/examples/examples/z_forward.rs index be9df7e2b0..1f6969766f 100644 --- a/examples/examples/z_forward.rs +++ b/examples/examples/z_forward.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; use zenoh_ext::SubscriberForward; diff --git a/examples/examples/z_get_liveliness.rs b/examples/examples/z_get_liveliness.rs index 53f7abc92a..d0040fcea4 100644 --- a/examples/examples/z_get_liveliness.rs +++ b/examples/examples/z_get_liveliness.rs @@ -14,7 +14,7 @@ use std::time::Duration; use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_info.rs b/examples/examples/z_info.rs index aa40ef62d4..606cdcbd16 100644 --- a/examples/examples/z_info.rs +++ b/examples/examples/z_info.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{prelude::*, session::ZenohId}; +use zenoh::session::ZenohId; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_liveliness.rs b/examples/examples/z_liveliness.rs index bf8890a267..1c51c2fce6 100644 --- a/examples/examples/z_liveliness.rs +++ b/examples/examples/z_liveliness.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_pong.rs b/examples/examples/z_pong.rs index 86b31d41f3..8794d6bc7a 100644 --- a/examples/examples/z_pong.rs +++ b/examples/examples/z_pong.rs @@ -21,7 +21,7 @@ fn main() { let (config, express) = parse_args(); - let session = zenoh::open(config).wait().unwrap().into_arc(); + let session = zenoh::open(config).wait().unwrap(); // The key expression to read the data from let key_expr_ping = keyexpr::new("test/ping").unwrap(); diff --git a/examples/examples/z_pull.rs b/examples/examples/z_pull.rs index 6716ef8cc5..1239f7347f 100644 --- a/examples/examples/z_pull.rs +++ b/examples/examples/z_pull.rs @@ -14,7 +14,7 @@ use std::time::Duration; use clap::Parser; -use zenoh::{handlers::RingChannel, key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{handlers::RingChannel, key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_queryable.rs b/examples/examples/z_queryable.rs index 4b950a0a33..905f8d50c9 100644 --- a/examples/examples/z_queryable.rs +++ b/examples/examples/z_queryable.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_queryable_shm.rs b/examples/examples/z_queryable_shm.rs index e92efbdc38..6801457d5a 100644 --- a/examples/examples/z_queryable_shm.rs +++ b/examples/examples/z_queryable_shm.rs @@ -15,7 +15,6 @@ use clap::Parser; use zenoh::{ bytes::ZBytes, key_expr::KeyExpr, - prelude::*, shm::{ zshm, BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, diff --git a/examples/examples/z_storage.rs b/examples/examples/z_storage.rs index f812c78094..360e00f9d1 100644 --- a/examples/examples/z_storage.rs +++ b/examples/examples/z_storage.rs @@ -19,7 +19,6 @@ use clap::Parser; use futures::select; use zenoh::{ key_expr::{keyexpr, KeyExpr}, - prelude::*, sample::{Sample, SampleKind}, Config, }; diff --git a/examples/examples/z_sub.rs b/examples/examples/z_sub.rs index 7f3a93c5fb..eca53a7849 100644 --- a/examples/examples/z_sub.rs +++ b/examples/examples/z_sub.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_sub_liveliness.rs b/examples/examples/z_sub_liveliness.rs index bb91c9f491..0b70d20786 100644 --- a/examples/examples/z_sub_liveliness.rs +++ b/examples/examples/z_sub_liveliness.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, sample::SampleKind, Config}; +use zenoh::{key_expr::KeyExpr, sample::SampleKind, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_sub_shm.rs b/examples/examples/z_sub_shm.rs index f45dab099d..1f35a2636e 100644 --- a/examples/examples/z_sub_shm.rs +++ b/examples/examples/z_sub_shm.rs @@ -14,7 +14,7 @@ use clap::Parser; #[cfg(all(feature = "shared-memory", feature = "unstable"))] use zenoh::shm::zshm; -use zenoh::{bytes::ZBytes, config::Config, key_expr::KeyExpr, prelude::*}; +use zenoh::{bytes::ZBytes, config::Config, key_expr::KeyExpr}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/plugins/zenoh-plugin-example/src/lib.rs b/plugins/zenoh-plugin-example/src/lib.rs index b7c494946d..086e23aaa8 100644 --- a/plugins/zenoh-plugin-example/src/lib.rs +++ b/plugins/zenoh-plugin-example/src/lib.rs @@ -36,7 +36,6 @@ use zenoh::{ key_expr::{keyexpr, KeyExpr}, prelude::ZResult, sample::Sample, - session::SessionDeclarations, }; use zenoh_plugin_trait::{plugin_long_version, plugin_version, Plugin, PluginControl}; diff --git a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs index aefdfd4f86..fbd0269498 100644 --- a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs +++ b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs @@ -18,7 +18,6 @@ use zenoh::{ config::Config, key_expr::keyexpr, qos::{CongestionControl, QoSBuilderTrait}, - session::SessionDeclarations, }; const HTML: &str = r#" diff --git a/plugins/zenoh-plugin-rest/src/lib.rs b/plugins/zenoh-plugin-rest/src/lib.rs index eb65a991d6..289fc9e055 100644 --- a/plugins/zenoh-plugin-rest/src/lib.rs +++ b/plugins/zenoh-plugin-rest/src/lib.rs @@ -47,7 +47,7 @@ use zenoh::{ prelude::*, query::{Parameters, QueryConsolidation, Reply, Selector, ZenohParameters}, sample::{Sample, SampleKind}, - session::{Session, SessionDeclarations}, + session::Session, }; use zenoh_plugin_trait::{plugin_long_version, plugin_version, Plugin, PluginControl}; diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs b/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs index 4766914e21..a9302cd8cf 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs @@ -24,7 +24,7 @@ use std::{ use flume::{Receiver, Sender}; use futures::{pin_mut, select, FutureExt}; use tokio::{sync::RwLock, time::interval}; -use zenoh::{key_expr::keyexpr, prelude::*}; +use zenoh::key_expr::keyexpr; use zenoh_backend_traits::config::{ReplicaConfig, StorageConfig}; use crate::{backends_mgt::StoreIntercept, storages_mgt::StorageMessage}; diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs index d2147b137c..94e9d85d82 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs @@ -36,7 +36,7 @@ use zenoh::{ }, query::{ConsolidationMode, QueryTarget}, sample::{Sample, SampleBuilder, SampleKind, TimestampBuilderTrait}, - session::{Session, SessionDeclarations}, + session::Session, time::{Timestamp, NTP64}, }; use zenoh_backend_traits::{ diff --git a/zenoh-ext/examples/examples/z_query_sub.rs b/zenoh-ext/examples/examples/z_query_sub.rs index c819a2a831..1c1a3eab27 100644 --- a/zenoh-ext/examples/examples/z_query_sub.rs +++ b/zenoh-ext/examples/examples/z_query_sub.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::{arg, Parser}; -use zenoh::{config::Config, prelude::*, query::ReplyKeyExpr}; +use zenoh::{config::Config, query::ReplyKeyExpr}; use zenoh_ext::*; use zenoh_ext_examples::CommonArgs; diff --git a/zenoh-ext/src/publication_cache.rs b/zenoh-ext/src/publication_cache.rs index 9c1536c2a1..af548a3b6c 100644 --- a/zenoh-ext/src/publication_cache.rs +++ b/zenoh-ext/src/publication_cache.rs @@ -25,14 +25,13 @@ use zenoh::{ pubsub::FlumeSubscriber, query::{Query, Queryable, ZenohParameters}, sample::{Locality, Sample}, - session::{SessionDeclarations, SessionRef}, - Error, Resolvable, Resolve, Result as ZResult, + Error, Resolvable, Resolve, Result as ZResult, Session, }; /// The builder of PublicationCache, allowing to configure it. #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] pub struct PublicationCacheBuilder<'a, 'b, 'c> { - session: SessionRef<'a>, + session: &'a Session, pub_key_expr: ZResult>, queryable_prefix: Option>>, queryable_origin: Option, @@ -43,7 +42,7 @@ pub struct PublicationCacheBuilder<'a, 'b, 'c> { impl<'a, 'b, 'c> PublicationCacheBuilder<'a, 'b, 'c> { pub(crate) fn new( - session: SessionRef<'a>, + session: &'a Session, pub_key_expr: ZResult>, ) -> PublicationCacheBuilder<'a, 'b, 'c> { PublicationCacheBuilder { @@ -95,8 +94,8 @@ impl<'a, 'b, 'c> PublicationCacheBuilder<'a, 'b, 'c> { } } -impl<'a> Resolvable for PublicationCacheBuilder<'a, '_, '_> { - type To = ZResult>; +impl Resolvable for PublicationCacheBuilder<'_, '_, '_> { + type To = ZResult; } impl Wait for PublicationCacheBuilder<'_, '_, '_> { @@ -105,7 +104,7 @@ impl Wait for PublicationCacheBuilder<'_, '_, '_> { } } -impl<'a> IntoFuture for PublicationCacheBuilder<'a, '_, '_> { +impl IntoFuture for PublicationCacheBuilder<'_, '_, '_> { type Output = ::To; type IntoFuture = Ready<::To>; @@ -114,14 +113,14 @@ impl<'a> IntoFuture for PublicationCacheBuilder<'a, '_, '_> { } } -pub struct PublicationCache<'a> { - local_sub: FlumeSubscriber<'a>, - _queryable: Queryable<'a, flume::Receiver>, +pub struct PublicationCache { + local_sub: FlumeSubscriber, + _queryable: Queryable>, task: TerminatableTask, } -impl<'a> PublicationCache<'a> { - fn new(conf: PublicationCacheBuilder<'a, '_, '_>) -> ZResult> { +impl PublicationCache { + fn new(conf: PublicationCacheBuilder<'_, '_, '_>) -> ZResult { let key_expr = conf.pub_key_expr?; // the queryable_prefix (optional), and the key_expr for PublicationCache's queryable ("[]/") let (queryable_prefix, queryable_key_expr): (Option, KeyExpr) = @@ -258,7 +257,7 @@ impl<'a> PublicationCache<'a> { /// Undeclare this [`PublicationCache`]`. #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { ResolveFuture::new(async move { let PublicationCache { _queryable, diff --git a/zenoh-ext/src/querying_subscriber.rs b/zenoh-ext/src/querying_subscriber.rs index 224abfde87..893cbcbad0 100644 --- a/zenoh-ext/src/querying_subscriber.rs +++ b/zenoh-ext/src/querying_subscriber.rs @@ -28,9 +28,8 @@ use zenoh::{ pubsub::{Reliability, Subscriber}, query::{QueryConsolidation, QueryTarget, ReplyKeyExpr, Selector}, sample::{Locality, Sample, SampleBuilder, TimestampBuilderTrait}, - session::{SessionDeclarations, SessionRef}, time::Timestamp, - Error, Resolvable, Resolve, Result as ZResult, + Error, Resolvable, Resolve, Result as ZResult, Session, }; use crate::ExtractSample; @@ -38,7 +37,7 @@ use crate::ExtractSample; /// The builder of [`FetchingSubscriber`], allowing to configure it. #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] pub struct QueryingSubscriberBuilder<'a, 'b, KeySpace, Handler> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) key_space: KeySpace, pub(crate) reliability: Reliability, @@ -224,7 +223,7 @@ where Handler: IntoHandler<'static, Sample>, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } impl Wait for QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> @@ -362,7 +361,7 @@ pub struct FetchingSubscriberBuilder< > where TryIntoSample: ExtractSample, { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) key_space: KeySpace, pub(crate) reliability: Reliability, @@ -548,7 +547,7 @@ where Handler::Handler: Send, TryIntoSample: ExtractSample, { - type To = ZResult>; + type To = ZResult>; } impl< @@ -620,28 +619,29 @@ where /// } /// # } /// ``` -pub struct FetchingSubscriber<'a, Handler> { - subscriber: Subscriber<'a, ()>, +pub struct FetchingSubscriber { + subscriber: Subscriber<()>, callback: Arc, state: Arc>, handler: Handler, } -impl std::ops::Deref for FetchingSubscriber<'_, Handler> { +impl std::ops::Deref for FetchingSubscriber { type Target = Handler; fn deref(&self) -> &Self::Target { &self.handler } } -impl std::ops::DerefMut for FetchingSubscriber<'_, Handler> { +impl std::ops::DerefMut for FetchingSubscriber { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.handler } } -impl<'a, Handler> FetchingSubscriber<'a, Handler> { +impl FetchingSubscriber { fn new< + 'a, KeySpace, InputHandler, Fetch: FnOnce(Box) -> ZResult<()> + Send + Sync, @@ -724,7 +724,7 @@ impl<'a, Handler> FetchingSubscriber<'a, Handler> { /// Undeclare this [`FetchingSubscriber`]`. #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { self.subscriber.undeclare() } diff --git a/zenoh-ext/src/session_ext.rs b/zenoh-ext/src/session_ext.rs index 606f00743b..21f2fc5c6e 100644 --- a/zenoh-ext/src/session_ext.rs +++ b/zenoh-ext/src/session_ext.rs @@ -11,54 +11,13 @@ // Contributors: // ZettaScale Zenoh Team, // -use std::{convert::TryInto, sync::Arc}; -use zenoh::{ - key_expr::KeyExpr, - session::{Session, SessionRef}, - Error, -}; +use zenoh::{key_expr::KeyExpr, session::Session, Error}; use super::PublicationCacheBuilder; /// Some extensions to the [`zenoh::Session`](zenoh::Session) pub trait SessionExt<'s, 'a> { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'s self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; -} - -impl<'s, 'a> SessionExt<'s, 'a> for SessionRef<'a> { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'s self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublicationCacheBuilder::new(self.clone(), pub_key_expr.try_into().map_err(Into::into)) - } -} - -impl<'a> SessionExt<'a, 'a> for Session { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'a self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SessionRef::Borrow(self).declare_publication_cache(pub_key_expr) - } -} - -impl<'s> SessionExt<'s, 'static> for Arc { /// Examples: /// ``` /// # #[tokio::main] @@ -69,7 +28,7 @@ impl<'s> SessionExt<'s, 'static> for Arc { /// /// let mut config = zenoh::config::default(); /// config.timestamping.set_enabled(Some(Unique(true))); - /// let session = zenoh::open(config).await.unwrap().into_arc(); + /// let session = zenoh::open(config).await.unwrap(); /// let publication_cache = session.declare_publication_cache("key/expression").await.unwrap(); /// tokio::task::spawn(async move { /// publication_cache.key_expr(); @@ -79,11 +38,21 @@ impl<'s> SessionExt<'s, 'static> for Arc { fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( &'s self, pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'static, 'b, 'c> + ) -> PublicationCacheBuilder<'a, 'b, 'c> + where + TryIntoKeyExpr: TryInto>, + >>::Error: Into; +} + +impl<'a> SessionExt<'a, 'a> for Session { + fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( + &'a self, + pub_key_expr: TryIntoKeyExpr, + ) -> PublicationCacheBuilder<'a, 'b, 'c> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Shared(self.clone()).declare_publication_cache(pub_key_expr) + PublicationCacheBuilder::new(self, pub_key_expr.try_into().map_err(Into::into)) } } diff --git a/zenoh-ext/src/subscriber_ext.rs b/zenoh-ext/src/subscriber_ext.rs index a7356f86dc..434ec15234 100644 --- a/zenoh-ext/src/subscriber_ext.rs +++ b/zenoh-ext/src/subscriber_ext.rs @@ -32,7 +32,7 @@ pub trait SubscriberForward<'a, S> { type Output; fn forward(&'a mut self, sink: S) -> Self::Output; } -impl<'a, S> SubscriberForward<'a, S> for Subscriber<'_, flume::Receiver> +impl<'a, S> SubscriberForward<'a, S> for Subscriber> where S: futures::sink::Sink, { diff --git a/zenoh-ext/tests/liveliness.rs b/zenoh-ext/tests/liveliness.rs index 637d07ba57..51c8a79cd3 100644 --- a/zenoh-ext/tests/liveliness.rs +++ b/zenoh-ext/tests/liveliness.rs @@ -21,7 +21,7 @@ use zenoh::{ async fn test_liveliness_querying_subscriber_clique() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); @@ -99,7 +99,7 @@ async fn test_liveliness_querying_subscriber_clique() { async fn test_liveliness_querying_subscriber_brokered() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); diff --git a/zenoh/src/api/admin.rs b/zenoh/src/api/admin.rs index 8c20a275c1..7452431977 100644 --- a/zenoh/src/api/admin.rs +++ b/zenoh/src/api/admin.rs @@ -14,7 +14,7 @@ use std::{ collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, - sync::Arc, + sync::{Arc, Weak}, }; use zenoh_core::{Result as ZResult, Wait}; @@ -32,9 +32,9 @@ use super::{ key_expr::KeyExpr, queryable::Query, sample::{DataInfo, Locality, SampleKind}, - session::Session, subscriber::SubscriberKind, }; +use crate::api::session::SessionInner; lazy_static::lazy_static!( static ref KE_STARSTAR: &'static keyexpr = unsafe { keyexpr::from_str_unchecked("**") }; @@ -44,8 +44,8 @@ lazy_static::lazy_static!( static ref KE_LINK: &'static keyexpr = unsafe { keyexpr::from_str_unchecked("link") }; ); -pub(crate) fn init(session: &Session) { - if let Ok(own_zid) = keyexpr::new(&session.zid().to_string()) { +pub(crate) fn init(session: &Arc) { + if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { let admin_key = KeyExpr::from(*KE_PREFIX / own_zid / *KE_SESSION / *KE_STARSTAR) .to_wire(session) .to_owned(); @@ -55,14 +55,18 @@ pub(crate) fn init(session: &Session) { true, Locality::SessionLocal, Arc::new({ - let session = session.clone(); - move |q| super::admin::on_admin_query(&session, q) + let session = Arc::downgrade(session); + move |q| { + if let Some(session) = Weak::upgrade(&session) { + on_admin_query(&session, q) + } + } }), ); } } -pub(crate) fn on_admin_query(session: &Session, query: Query) { +pub(crate) fn on_admin_query(session: &SessionInner, query: Query) { fn reply_peer(own_zid: &keyexpr, query: &Query, peer: TransportPeer) { let zid = peer.zid.to_string(); if let Ok(zid) = keyexpr::new(&zid) { @@ -104,7 +108,7 @@ pub(crate) fn on_admin_query(session: &Session, query: Query) { } } - if let Ok(own_zid) = keyexpr::new(&session.zid().to_string()) { + if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { for transport in zenoh_runtime::ZRuntime::Net .block_in_place(session.runtime.manager().get_transports_unicast()) { @@ -124,14 +128,12 @@ pub(crate) fn on_admin_query(session: &Session, query: Query) { #[derive(Clone)] pub(crate) struct Handler { - pub(crate) session: Arc, + pub(crate) session: Weak, } impl Handler { - pub(crate) fn new(session: Session) -> Self { - Self { - session: Arc::new(session), - } + pub(crate) fn new(session: Weak) -> Self { + Self { session } } } @@ -157,7 +159,10 @@ impl TransportMulticastEventHandler for Handler { &self, peer: zenoh_transport::TransportPeer, ) -> ZResult> { - if let Ok(own_zid) = keyexpr::new(&self.session.zid().to_string()) { + let Some(session) = Weak::upgrade(&self.session) else { + bail!("session closed"); + }; + if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { if let Ok(zid) = keyexpr::new(&peer.zid.to_string()) { let expr = WireExpr::from( &(*KE_PREFIX / own_zid / *KE_SESSION / *KE_TRANSPORT_UNICAST / zid), @@ -167,7 +172,7 @@ impl TransportMulticastEventHandler for Handler { encoding: Some(Encoding::APPLICATION_JSON), ..Default::default() }; - self.session.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( true, &expr, Some(info), @@ -200,7 +205,7 @@ impl TransportMulticastEventHandler for Handler { pub(crate) struct PeerHandler { pub(crate) expr: WireExpr<'static>, - pub(crate) session: Arc, + pub(crate) session: Weak, } impl TransportPeerEventHandler for PeerHandler { @@ -209,13 +214,16 @@ impl TransportPeerEventHandler for PeerHandler { } fn new_link(&self, link: zenoh_link::Link) { + let Some(session) = Weak::upgrade(&self.session) else { + return; + }; let mut s = DefaultHasher::new(); link.hash(&mut s); let info = DataInfo { encoding: Some(Encoding::APPLICATION_JSON), ..Default::default() }; - self.session.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( true, &self .expr @@ -231,13 +239,16 @@ impl TransportPeerEventHandler for PeerHandler { } fn del_link(&self, link: zenoh_link::Link) { + let Some(session) = Weak::upgrade(&self.session) else { + return; + }; let mut s = DefaultHasher::new(); link.hash(&mut s); let info = DataInfo { kind: SampleKind::Delete, ..Default::default() }; - self.session.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( true, &self .expr @@ -255,11 +266,14 @@ impl TransportPeerEventHandler for PeerHandler { fn closing(&self) {} fn closed(&self) { + let Some(session) = Weak::upgrade(&self.session) else { + return; + }; let info = DataInfo { kind: SampleKind::Delete, ..Default::default() }; - self.session.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( true, &self.expr, Some(info), diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index 8a6961ac55..957bee62f8 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -20,16 +20,18 @@ use zenoh_protocol::{core::CongestionControl, network::Mapping}; #[cfg(feature = "unstable")] use crate::api::sample::SourceInfo; -use crate::api::{ - builders::sample::{ - EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait, TimestampBuilderTrait, +use crate::{ + api::{ + builders::sample::{ + EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait, TimestampBuilderTrait, + }, + bytes::{OptionZBytes, ZBytes}, + encoding::Encoding, + key_expr::KeyExpr, + publisher::{Priority, Publisher}, + sample::{Locality, SampleKind}, }, - bytes::{OptionZBytes, ZBytes}, - encoding::Encoding, - key_expr::KeyExpr, - publisher::{Priority, Publisher}, - sample::{Locality, SampleKind}, - session::SessionRef, + Session, }; pub type SessionPutBuilder<'a, 'b> = @@ -245,8 +247,8 @@ impl IntoFuture for PublicationBuilder, PublicationBuil /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[derive(Debug)] -pub struct PublisherBuilder<'a, 'b: 'a> { - pub(crate) session: SessionRef<'a>, +pub struct PublisherBuilder<'a, 'b> { + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) encoding: Encoding, pub(crate) congestion_control: CongestionControl, @@ -260,7 +262,7 @@ pub struct PublisherBuilder<'a, 'b: 'a> { impl<'a, 'b> Clone for PublisherBuilder<'a, 'b> { fn clone(&self) -> Self { Self { - session: self.session.clone(), + session: self.session, key_expr: match &self.key_expr { Ok(k) => Ok(k.clone()), Err(e) => Err(zerror!("Cloned KE Error: {}", e).into()), @@ -324,9 +326,9 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { } // internal function for performing the publication - fn create_one_shot_publisher(self) -> ZResult> { + fn create_one_shot_publisher(self) -> ZResult> { Ok(Publisher { - session: self.session, + session: self.session.clone().0, id: 0, // This is a one shot Publisher key_expr: self.key_expr?, encoding: self.encoding, @@ -344,15 +346,15 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { } impl<'a, 'b> Resolvable for PublisherBuilder<'a, 'b> { - type To = ZResult>; + type To = ZResult>; } impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { fn wait(self) -> ::To { let mut key_expr = self.key_expr?; - if !key_expr.is_fully_optimized(&self.session) { - let session_id = self.session.id; - let expr_id = self.session.declare_prefix(key_expr.as_str()).wait(); + if !key_expr.is_fully_optimized(&self.session.0) { + let session_id = self.session.0.id; + let expr_id = self.session.0.declare_prefix(key_expr.as_str()).wait()?; let prefix_len = key_expr .len() .try_into() @@ -380,23 +382,24 @@ impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { } } } - self.session - .declare_publisher_inner(key_expr.clone(), self.destination) - .map(|id| Publisher { - session: self.session, - id, - key_expr, - encoding: self.encoding, - congestion_control: self.congestion_control, - priority: self.priority, - is_express: self.is_express, - destination: self.destination, - #[cfg(feature = "unstable")] - reliability: self.reliability, - #[cfg(feature = "unstable")] - matching_listeners: Default::default(), - undeclare_on_drop: true, - }) + let id = self + .session + .0 + .declare_publisher_inner(key_expr.clone(), self.destination)?; + Ok(Publisher { + session: self.session.0.clone(), + id, + key_expr, + encoding: self.encoding, + congestion_control: self.congestion_control, + priority: self.priority, + is_express: self.is_express, + destination: self.destination, + #[cfg(feature = "unstable")] + reliability: self.reliability, + #[cfg(feature = "unstable")]matching_listeners: Default::default(), + undeclare_on_drop: true, + }) } } diff --git a/zenoh/src/api/info.rs b/zenoh/src/api/info.rs index 32bed0eb53..88f8dd57b7 100644 --- a/zenoh/src/api/info.rs +++ b/zenoh/src/api/info.rs @@ -19,7 +19,7 @@ use zenoh_config::wrappers::ZenohId; use zenoh_core::{Resolvable, Wait}; use zenoh_protocol::core::WhatAmI; -use super::session::SessionRef; +use crate::net::runtime::Runtime; /// A builder retuned by [`SessionInfo::zid()`](SessionInfo::zid) that allows /// to access the [`ZenohId`] of the current zenoh [`Session`](crate::Session). @@ -35,9 +35,8 @@ use super::session::SessionRef; /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct ZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for ZenohIdBuilder<'a> { @@ -46,7 +45,7 @@ impl<'a> Resolvable for ZenohIdBuilder<'a> { impl<'a> Wait for ZenohIdBuilder<'a> { fn wait(self) -> Self::To { - self.session.runtime.zid() + self.runtime.zid() } } @@ -75,9 +74,8 @@ impl<'a> IntoFuture for ZenohIdBuilder<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct RoutersZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for RoutersZenohIdBuilder<'a> { @@ -88,7 +86,7 @@ impl<'a> Wait for RoutersZenohIdBuilder<'a> { fn wait(self) -> Self::To { Box::new( zenoh_runtime::ZRuntime::Application - .block_in_place(self.session.runtime.manager().get_transports_unicast()) + .block_in_place(self.runtime.manager().get_transports_unicast()) .into_iter() .filter_map(|s| { s.get_whatami() @@ -125,9 +123,8 @@ impl<'a> IntoFuture for RoutersZenohIdBuilder<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct PeersZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for PeersZenohIdBuilder<'a> { @@ -138,7 +135,7 @@ impl<'a> Wait for PeersZenohIdBuilder<'a> { fn wait(self) -> ::To { Box::new( zenoh_runtime::ZRuntime::Application - .block_in_place(self.session.runtime.manager().get_transports_unicast()) + .block_in_place(self.runtime.manager().get_transports_unicast()) .into_iter() .filter_map(|s| { s.get_whatami() @@ -173,11 +170,11 @@ impl<'a> IntoFuture for PeersZenohIdBuilder<'a> { /// let zid = info.zid().await; /// # } /// ``` -pub struct SessionInfo<'a> { - pub(crate) session: SessionRef<'a>, +pub struct SessionInfo { + pub(crate) runtime: Runtime, } -impl SessionInfo<'_> { +impl SessionInfo { /// Return the [`ZenohId`] of the current zenoh [`Session`](crate::Session). /// /// # Examples @@ -192,7 +189,7 @@ impl SessionInfo<'_> { /// ``` pub fn zid(&self) -> ZenohIdBuilder<'_> { ZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } @@ -212,7 +209,7 @@ impl SessionInfo<'_> { /// ``` pub fn routers_zid(&self) -> RoutersZenohIdBuilder<'_> { RoutersZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } @@ -231,7 +228,7 @@ impl SessionInfo<'_> { /// ``` pub fn peers_zid(&self) -> PeersZenohIdBuilder<'_> { PeersZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } } diff --git a/zenoh/src/api/key_expr.rs b/zenoh/src/api/key_expr.rs index 0f0d13a69c..6ed0cbcea3 100644 --- a/zenoh/src/api/key_expr.rs +++ b/zenoh/src/api/key_expr.rs @@ -25,7 +25,7 @@ use zenoh_protocol::{ }; use zenoh_result::ZResult; -use super::session::{Session, UndeclarableSealed}; +use super::session::{Session, SessionInner, UndeclarableSealed}; use crate::net::primitives::Primitives; #[derive(Clone, Debug)] @@ -492,7 +492,7 @@ impl<'a> KeyExpr<'a> { //pub(crate) fn is_optimized(&self, session: &Session) -> bool { // matches!(&self.0, KeyExprInner::Wire { expr_id, session_id, .. } | KeyExprInner::BorrowedWire { expr_id, session_id, .. } if *expr_id != 0 && session.id == *session_id) //} - pub(crate) fn is_fully_optimized(&self, session: &Session) -> bool { + pub(crate) fn is_fully_optimized(&self, session: &SessionInner) -> bool { match &self.0 { KeyExprInner::Wire { key_expr, @@ -509,7 +509,7 @@ impl<'a> KeyExpr<'a> { _ => false, } } - pub(crate) fn to_wire(&'a self, session: &Session) -> WireExpr<'a> { + pub(crate) fn to_wire(&'a self, session: &SessionInner) -> WireExpr<'a> { match &self.0 { KeyExprInner::Wire { key_expr, @@ -594,7 +594,7 @@ impl Wait for KeyExprUndeclaration<'_> { session_id, .. } if *prefix_len as usize == key_expr.len() => { - if *session_id == session.id { + if *session_id == session.0.id { *expr_id } else { return Err(zerror!("Failed to undeclare {}, as it was declared by an other Session", expr).into()) @@ -607,7 +607,7 @@ impl Wait for KeyExprUndeclaration<'_> { session_id, .. } if *prefix_len as usize == key_expr.len() => { - if *session_id == session.id { + if *session_id == session.0.id { *expr_id } else { return Err(zerror!("Failed to undeclare {}, as it was declared by an other Session", expr).into()) @@ -616,10 +616,10 @@ impl Wait for KeyExprUndeclaration<'_> { _ => return Err(zerror!("Failed to undeclare {}, make sure you use the result of `Session::declare_keyexpr` to call `Session::undeclare`", expr).into()), }; tracing::trace!("undeclare_keyexpr({:?})", expr_id); - let mut state = zwrite!(session.state); + let mut state = zwrite!(session.0.state); state.local_resources.remove(&expr_id); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(zenoh_protocol::network::Declare { interest_id: None, diff --git a/zenoh/src/api/liveliness.rs b/zenoh/src/api/liveliness.rs index f22de66b02..50bcf9da67 100644 --- a/zenoh/src/api/liveliness.rs +++ b/zenoh/src/api/liveliness.rs @@ -16,7 +16,7 @@ use std::{ convert::TryInto, future::{IntoFuture, Ready}, mem::size_of, - sync::Arc, + sync::{Arc, Weak}, time::Duration, }; @@ -29,11 +29,11 @@ use super::{ key_expr::KeyExpr, query::Reply, sample::{Locality, Sample}, - session::{Session, SessionRef, UndeclarableSealed}, + session::{Session, UndeclarableSealed}, subscriber::{Subscriber, SubscriberInner}, Id, }; -use crate::api::session::MaybeWeakSessionRef; +use crate::api::session::SessionInner; /// A structure with functions to declare a /// [`LivelinessToken`](LivelinessToken), query @@ -97,7 +97,7 @@ use crate::api::session::MaybeWeakSessionRef; /// ``` #[zenoh_macros::unstable] pub struct Liveliness<'a> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, } #[zenoh_macros::unstable] @@ -132,7 +132,7 @@ impl<'a> Liveliness<'a> { >>::Error: Into, { LivelinessTokenBuilder { - session: self.session.clone(), + session: self.session, key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), } } @@ -169,7 +169,7 @@ impl<'a> Liveliness<'a> { >>::Error: Into, { LivelinessSubscriberBuilder { - session: self.session.clone(), + session: self.session, key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), handler: DefaultHandler::default(), } @@ -207,11 +207,11 @@ impl<'a> Liveliness<'a> { { let key_expr = key_expr.try_into().map_err(Into::into); let timeout = { - let conf = self.session.runtime.config().lock(); + let conf = self.session.0.runtime.config().lock(); Duration::from_millis(unwrap_or_default!(conf.queries_default_timeout())) }; LivelinessGetBuilder { - session: &self.session, + session: self.session, key_expr, timeout, handler: DefaultHandler::default(), @@ -239,13 +239,13 @@ impl<'a> Liveliness<'a> { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessTokenBuilder<'a, 'b> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, } #[zenoh_macros::unstable] -impl<'a> Resolvable for LivelinessTokenBuilder<'a, '_> { - type To = ZResult>; +impl Resolvable for LivelinessTokenBuilder<'_, '_> { + type To = ZResult; } #[zenoh_macros::unstable] @@ -254,13 +254,13 @@ impl Wait for LivelinessTokenBuilder<'_, '_> { fn wait(self) -> ::To { let session = self.session; let key_expr = self.key_expr?.into_owned(); - let undeclare_on_drop = true; session + .0 .declare_liveliness_inner(&key_expr) .map(|tok_state| LivelinessToken { - session: MaybeWeakSessionRef::new(session, !undeclare_on_drop), + session: Arc::downgrade(&self.session.0), state: tok_state, - undeclare_on_drop, + undeclare_on_drop: true, }) } } @@ -310,8 +310,8 @@ pub(crate) struct LivelinessTokenState { /// ``` #[zenoh_macros::unstable] #[derive(Debug)] -pub struct LivelinessToken<'a> { - session: MaybeWeakSessionRef<'a>, +pub struct LivelinessToken { + session: Weak, state: Arc, undeclare_on_drop: bool, } @@ -336,22 +336,22 @@ pub struct LivelinessToken<'a> { /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[zenoh_macros::unstable] -pub struct LivelinessTokenUndeclaration<'a>(LivelinessToken<'a>); +pub struct LivelinessTokenUndeclaration(LivelinessToken); #[zenoh_macros::unstable] -impl Resolvable for LivelinessTokenUndeclaration<'_> { +impl Resolvable for LivelinessTokenUndeclaration { type To = ZResult<()>; } #[zenoh_macros::unstable] -impl Wait for LivelinessTokenUndeclaration<'_> { +impl Wait for LivelinessTokenUndeclaration { fn wait(mut self) -> ::To { self.0.undeclare_impl() } } #[zenoh_macros::unstable] -impl<'a> IntoFuture for LivelinessTokenUndeclaration<'a> { +impl IntoFuture for LivelinessTokenUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -361,7 +361,7 @@ impl<'a> IntoFuture for LivelinessTokenUndeclaration<'a> { } #[zenoh_macros::unstable] -impl<'a> LivelinessToken<'a> { +impl LivelinessToken { /// Undeclare the [`LivelinessToken`]. /// /// # Examples @@ -381,7 +381,7 @@ impl<'a> LivelinessToken<'a> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { UndeclarableSealed::undeclare_inner(self, ()) } @@ -396,8 +396,8 @@ impl<'a> LivelinessToken<'a> { } #[zenoh_macros::unstable] -impl<'a> UndeclarableSealed<()> for LivelinessToken<'a> { - type Undeclaration = LivelinessTokenUndeclaration<'a>; +impl UndeclarableSealed<()> for LivelinessToken { + type Undeclaration = LivelinessTokenUndeclaration; fn undeclare_inner(self, _: ()) -> Self::Undeclaration { LivelinessTokenUndeclaration(self) @@ -405,7 +405,7 @@ impl<'a> UndeclarableSealed<()> for LivelinessToken<'a> { } #[zenoh_macros::unstable] -impl Drop for LivelinessToken<'_> { +impl Drop for LivelinessToken { fn drop(&mut self) { if self.undeclare_on_drop { if let Err(error) = self.undeclare_impl() { @@ -435,7 +435,7 @@ impl Drop for LivelinessToken<'_> { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessSubscriberBuilder<'a, 'b, Handler> { - pub session: SessionRef<'a>, + pub session: &'a Session, pub key_expr: ZResult>, pub handler: Handler, } @@ -558,7 +558,7 @@ where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } #[zenoh_macros::unstable] @@ -574,22 +574,20 @@ where let key_expr = self.key_expr?; let session = self.session; let (callback, handler) = self.handler.into_handler(); - let undeclare_on_drop = size_of::() > 0; session + .0 .declare_liveliness_subscriber_inner(&key_expr, Locality::default(), callback) - .map(|sub_state| { - Subscriber { - inner: SubscriberInner { - #[cfg(feature = "unstable")] - session_id: session.zid(), - session: MaybeWeakSessionRef::new(session, !undeclare_on_drop), - state: sub_state, - kind: SubscriberKind::LivelinessSubscriber, - // `size_of::() == 0` means callback-only subscriber - undeclare_on_drop, - }, - handler, - } + .map(|sub_state| Subscriber { + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: Arc::downgrade(&self.session.0), + state: sub_state, + kind: SubscriberKind::LivelinessSubscriber, + // `size_of::() == 0` means callback-only subscriber + undeclare_on_drop: size_of::() > 0, + }, + handler, }) } } @@ -775,6 +773,7 @@ where fn wait(self) -> ::To { let (callback, receiver) = self.handler.into_handler(); self.session + .0 .liveliness_query(&self.key_expr?, self.timeout, callback) .map(|_| receiver) } diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index 0661ad3dec..2777b52b8a 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -17,6 +17,7 @@ use std::{ fmt, future::{IntoFuture, Ready}, pin::Pin, + sync::Arc, task::{Context, Poll}, }; @@ -35,10 +36,7 @@ use { handlers::{Callback, DefaultHandler, IntoHandler}, sample::SourceInfo, }, - std::{ - collections::HashSet, - sync::{Arc, Mutex}, - }, + std::{collections::HashSet, sync::Mutex}, zenoh_config::wrappers::EntityGlobalId, zenoh_protocol::core::EntityGlobalIdProto, }; @@ -52,10 +50,10 @@ use super::{ encoding::Encoding, key_expr::KeyExpr, sample::{DataInfo, Locality, QoS, Sample, SampleFields, SampleKind}, - session::{SessionRef, UndeclarableSealed}, + session::UndeclarableSealed, }; use crate::{ - api::{subscriber::SubscriberKind, Id}, + api::{session::SessionInner, subscriber::SubscriberKind, Id}, net::primitives::Primitives, }; @@ -75,35 +73,6 @@ impl fmt::Debug for PublisherState { } } -#[zenoh_macros::unstable] -#[derive(Clone)] -pub enum PublisherRef<'a> { - Borrow(&'a Publisher<'a>), - Shared(Arc>), -} - -#[zenoh_macros::unstable] -impl<'a> std::ops::Deref for PublisherRef<'a> { - type Target = Publisher<'a>; - - fn deref(&self) -> &Self::Target { - match self { - PublisherRef::Borrow(b) => b, - PublisherRef::Shared(s) => s, - } - } -} - -#[zenoh_macros::unstable] -impl std::fmt::Debug for PublisherRef<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PublisherRef::Borrow(b) => Publisher::fmt(b, f), - PublisherRef::Shared(s) => Publisher::fmt(s, f), - } - } -} - /// A publisher that allows to send data through a stream. /// /// Publishers are automatically undeclared when dropped. @@ -114,7 +83,7 @@ impl std::fmt::Debug for PublisherRef<'_> { /// # async fn main() { /// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.put("value").await.unwrap(); /// # } @@ -129,7 +98,7 @@ impl std::fmt::Debug for PublisherRef<'_> { /// use futures::StreamExt; /// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut subscriber = session.declare_subscriber("key/expression").await.unwrap(); /// let publisher = session.declare_publisher("another/key/expression").await.unwrap(); /// subscriber.stream().map(Ok).forward(publisher).await.unwrap(); @@ -137,7 +106,7 @@ impl std::fmt::Debug for PublisherRef<'_> { /// ``` #[derive(Debug, Clone)] pub struct Publisher<'a> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: Arc, pub(crate) id: Id, pub(crate) key_expr: KeyExpr<'a>, pub(crate) encoding: Encoding, @@ -171,7 +140,7 @@ impl<'a> Publisher<'a> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.session.zid().into(), + zid: self.session.runtime.zid().into(), eid: self.id, } .into() @@ -200,42 +169,6 @@ impl<'a> Publisher<'a> { self.priority } - /// Consumes the given `Publisher`, returning a thread-safe reference-counting - /// pointer to it (`Arc`). This is equivalent to `Arc::new(Publisher)`. - /// - /// This is useful to share ownership of the `Publisher` between several threads - /// and tasks. It also allows to create [`MatchingListener`] with static - /// lifetime that can be moved to several threads and tasks. - /// - /// Note: the given zenoh `Publisher` will be undeclared when the last reference to - /// it is dropped. - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - pub fn into_arc(self) -> std::sync::Arc { - std::sync::Arc::new(self) - } - /// Put data. /// /// # Examples @@ -244,7 +177,7 @@ impl<'a> Publisher<'a> { /// # async fn main() { /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.put("value").await.unwrap(); /// # } @@ -275,7 +208,7 @@ impl<'a> Publisher<'a> { /// # async fn main() { /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.delete().await.unwrap(); /// # } @@ -302,7 +235,7 @@ impl<'a> Publisher<'a> { /// # async fn main() { /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_subscribers: bool = publisher /// .matching_status() @@ -343,9 +276,9 @@ impl<'a> Publisher<'a> { /// # } /// ``` #[zenoh_macros::unstable] - pub fn matching_listener(&self) -> MatchingListenerBuilder<'_, DefaultHandler> { + pub fn matching_listener(&self) -> MatchingListenerBuilder<'_, 'a, DefaultHandler> { MatchingListenerBuilder { - publisher: PublisherRef::Borrow(self), + publisher: self, handler: DefaultHandler::default(), } } @@ -381,94 +314,6 @@ impl<'a> Publisher<'a> { } } -/// Functions to create zenoh entities with `'static` lifetime. -/// -/// This trait contains functions to create zenoh entities like -/// [`MatchingListener`] with a `'static` lifetime. -/// This is useful to move zenoh entities to several threads and tasks. -/// -/// This trait is implemented for `Arc`. -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); -/// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); -/// let matching_listener = publisher.matching_listener().await.unwrap(); -/// -/// tokio::task::spawn(async move { -/// while let Ok(matching_status) = matching_listener.recv_async().await { -/// if matching_status.matching_subscribers() { -/// println!("Publisher has matching subscribers."); -/// } else { -/// println!("Publisher has NO MORE matching subscribers."); -/// } -/// } -/// }).await; -/// # } -/// ``` -#[zenoh_macros::unstable] -pub trait PublisherDeclarations { - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - fn matching_listener(&self) -> MatchingListenerBuilder<'static, DefaultHandler>; -} - -#[zenoh_macros::unstable] -impl PublisherDeclarations for std::sync::Arc> { - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - fn matching_listener(&self) -> MatchingListenerBuilder<'static, DefaultHandler> { - MatchingListenerBuilder { - publisher: PublisherRef::Shared(self.clone()), - handler: DefaultHandler::default(), - } - } -} - impl<'a> UndeclarableSealed<()> for Publisher<'a> { type Undeclaration = PublisherUndeclaration<'a>; @@ -753,7 +598,7 @@ impl TryFrom for Priority { /// # async fn main() { /// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_status = publisher.matching_status().await.unwrap(); /// # } @@ -774,7 +619,7 @@ impl MatchingStatus { /// # async fn main() { /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_subscribers: bool = publisher /// .matching_status() @@ -791,13 +636,13 @@ impl MatchingStatus { /// A builder for initializing a [`MatchingListener`]. #[zenoh_macros::unstable] #[derive(Debug)] -pub struct MatchingListenerBuilder<'a, Handler> { - pub(crate) publisher: PublisherRef<'a>, +pub struct MatchingListenerBuilder<'a, 'b, Handler> { + pub(crate) publisher: &'a Publisher<'b>, pub handler: Handler, } #[zenoh_macros::unstable] -impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { +impl<'a, 'b> MatchingListenerBuilder<'a, 'b, DefaultHandler> { /// Receive the MatchingStatuses for this listener with a callback. /// /// # Examples @@ -823,7 +668,7 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ``` #[inline] #[zenoh_macros::unstable] - pub fn callback(self, callback: Callback) -> MatchingListenerBuilder<'a, Callback> + pub fn callback(self, callback: Callback) -> MatchingListenerBuilder<'a, 'b, Callback> where Callback: Fn(MatchingStatus) + Send + Sync + 'static, { @@ -860,7 +705,7 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { pub fn callback_mut( self, callback: CallbackMut, - ) -> MatchingListenerBuilder<'a, impl Fn(MatchingStatus) + Send + Sync + 'static> + ) -> MatchingListenerBuilder<'a, 'b, impl Fn(MatchingStatus) + Send + Sync + 'static> where CallbackMut: FnMut(MatchingStatus) + Send + Sync + 'static, { @@ -893,7 +738,7 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ``` #[inline] #[zenoh_macros::unstable] - pub fn with(self, handler: Handler) -> MatchingListenerBuilder<'a, Handler> + pub fn with(self, handler: Handler) -> MatchingListenerBuilder<'a, 'b, Handler> where Handler: IntoHandler<'static, MatchingStatus>, { @@ -906,7 +751,7 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { } #[zenoh_macros::unstable] -impl<'a, Handler> Resolvable for MatchingListenerBuilder<'a, Handler> +impl<'a, 'b, Handler> Resolvable for MatchingListenerBuilder<'a, 'b, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, @@ -915,7 +760,7 @@ where } #[zenoh_macros::unstable] -impl<'a, Handler> Wait for MatchingListenerBuilder<'a, Handler> +impl<'a, 'b, Handler> Wait for MatchingListenerBuilder<'a, 'b, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, @@ -926,11 +771,11 @@ where let state = self .publisher .session - .declare_matches_listener_inner(&self.publisher, callback)?; + .declare_matches_listener_inner(self.publisher, callback)?; zlock!(self.publisher.matching_listeners).insert(state.id); Ok(MatchingListener { listener: MatchingListenerInner { - publisher: self.publisher, + publisher: self.publisher.clone(), state, }, receiver, @@ -939,7 +784,7 @@ where } #[zenoh_macros::unstable] -impl<'a, Handler> IntoFuture for MatchingListenerBuilder<'a, Handler> +impl<'a, 'b, Handler> IntoFuture for MatchingListenerBuilder<'a, 'b, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, @@ -963,8 +808,8 @@ pub(crate) struct MatchingListenerState { } #[zenoh_macros::unstable] -impl std::fmt::Debug for MatchingListenerState { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Debug for MatchingListenerState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MatchingListener") .field("id", &self.id) .field("key_expr", &self.key_expr) @@ -974,7 +819,7 @@ impl std::fmt::Debug for MatchingListenerState { #[zenoh_macros::unstable] pub(crate) struct MatchingListenerInner<'a> { - pub(crate) publisher: PublisherRef<'a>, + pub(crate) publisher: Publisher<'a>, pub(crate) state: Arc, } @@ -1107,7 +952,7 @@ mod tests { use zenoh_config::Config; use zenoh_core::Wait; - use crate::api::{sample::SampleKind, session::SessionDeclarations}; + use crate::api::sample::SampleKind; #[cfg(feature = "internal")] #[test] diff --git a/zenoh/src/api/query.rs b/zenoh/src/api/query.rs index 2a1016db5f..bea028ff97 100644 --- a/zenoh/src/api/query.rs +++ b/zenoh/src/api/query.rs @@ -489,6 +489,7 @@ where parameters, } = self.selector?; self.session + .0 .query( &key_expr, ¶meters, diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 56b26fa36e..37a5b6bc21 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -16,7 +16,7 @@ use std::{ future::{IntoFuture, Ready}, mem::size_of, ops::{Deref, DerefMut}, - sync::Arc, + sync::{Arc, Weak}, }; use tracing::error; @@ -50,11 +50,12 @@ use crate::{ publisher::Priority, sample::{Locality, QoSBuilder, Sample, SampleKind}, selector::Selector, - session::{MaybeWeakSessionRef, SessionRef, UndeclarableSealed}, + session::{SessionInner, UndeclarableSealed}, value::Value, Id, }, net::primitives::Primitives, + Session, }; pub(crate) struct QueryInner { @@ -539,10 +540,10 @@ impl fmt::Debug for QueryableState { } #[derive(Debug)] -pub(crate) struct QueryableInner<'a> { +pub(crate) struct QueryableInner { #[cfg(feature = "unstable")] pub(crate) session_id: ZenohId, - pub(crate) session: MaybeWeakSessionRef<'a>, + pub(crate) session: Weak, pub(crate) state: Arc, // Queryable is undeclared on drop unless its handler is a ZST, i.e. it is callback-only pub(crate) undeclare_on_drop: bool, @@ -562,19 +563,19 @@ pub(crate) struct QueryableInner<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct QueryableUndeclaration<'a, Handler>(Queryable<'a, Handler>); +pub struct QueryableUndeclaration(Queryable); -impl Resolvable for QueryableUndeclaration<'_, Handler> { +impl Resolvable for QueryableUndeclaration { type To = ZResult<()>; } -impl Wait for QueryableUndeclaration<'_, Handler> { +impl Wait for QueryableUndeclaration { fn wait(mut self) -> ::To { self.0.undeclare_impl() } } -impl IntoFuture for QueryableUndeclaration<'_, Handler> { +impl IntoFuture for QueryableUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -598,7 +599,7 @@ impl IntoFuture for QueryableUndeclaration<'_, Handler> { #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[derive(Debug)] pub struct QueryableBuilder<'a, 'b, Handler> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) complete: bool, pub(crate) origin: Locality, @@ -792,12 +793,12 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// ``` #[non_exhaustive] #[derive(Debug)] -pub struct Queryable<'a, Handler> { - pub(crate) inner: QueryableInner<'a>, +pub struct Queryable { + pub(crate) inner: QueryableInner, pub(crate) handler: Handler, } -impl<'a, Handler> Queryable<'a, Handler> { +impl Queryable { /// Returns the [`EntityGlobalId`] of this Queryable. /// /// # Examples @@ -852,9 +853,9 @@ impl<'a, Handler> Queryable<'a, Handler> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a + pub fn undeclare(self) -> impl Resolve> where - Handler: Send + 'a, + Handler: Send, { UndeclarableSealed::undeclare_inner(self, ()) } @@ -869,7 +870,7 @@ impl<'a, Handler> Queryable<'a, Handler> { } } -impl Drop for Queryable<'_, Handler> { +impl Drop for Queryable { fn drop(&mut self) { if self.inner.undeclare_on_drop { if let Err(error) = self.undeclare_impl() { @@ -879,15 +880,15 @@ impl Drop for Queryable<'_, Handler> { } } -impl<'a, Handler: Send + 'a> UndeclarableSealed<()> for Queryable<'a, Handler> { - type Undeclaration = QueryableUndeclaration<'a, Handler>; +impl UndeclarableSealed<()> for Queryable { + type Undeclaration = QueryableUndeclaration; fn undeclare_inner(self, _: ()) -> Self::Undeclaration { QueryableUndeclaration(self) } } -impl Deref for Queryable<'_, Handler> { +impl Deref for Queryable { type Target = Handler; fn deref(&self) -> &Self::Target { @@ -895,21 +896,21 @@ impl Deref for Queryable<'_, Handler> { } } -impl DerefMut for Queryable<'_, Handler> { +impl DerefMut for Queryable { fn deref_mut(&mut self) -> &mut Self::Target { self.handler_mut() } } -impl<'a, Handler> Resolvable for QueryableBuilder<'a, '_, Handler> +impl Resolvable for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } -impl<'a, Handler> Wait for QueryableBuilder<'a, '_, Handler> +impl Wait for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, @@ -917,31 +918,29 @@ where fn wait(self) -> ::To { let session = self.session; let (callback, receiver) = self.handler.into_handler(); - let undeclare_on_drop = size_of::() > 0; session + .0 .declare_queryable_inner( - &self.key_expr?.to_wire(&session), + &self.key_expr?.to_wire(&session.0), self.complete, self.origin, callback, ) - .map(|qable_state| { - Queryable { - inner: QueryableInner { - #[cfg(feature = "unstable")] - session_id: session.zid(), - session: MaybeWeakSessionRef::new(session, !undeclare_on_drop), - state: qable_state, - // `size_of::() == 0` means callback-only queryable - undeclare_on_drop, - }, - handler: receiver, - } + .map(|qable_state| Queryable { + inner: QueryableInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: Arc::downgrade(&self.session.0), + state: qable_state, + // `size_of::() == 0` means callback-only queryable + undeclare_on_drop: size_of::() > 0, + }, + handler: receiver, }) } } -impl<'a, Handler> IntoFuture for QueryableBuilder<'a, '_, Handler> +impl IntoFuture for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index 231ab85d6d..945a469bff 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -16,7 +16,6 @@ use std::{ convert::TryInto, fmt, future::{IntoFuture, Ready}, - ops::Deref, sync::{ atomic::{AtomicU16, Ordering}, Arc, RwLock, Weak, @@ -174,6 +173,14 @@ impl SessionState { } impl SessionState { + #[inline] + pub(crate) fn primitives(&self) -> ZResult> { + self.primitives + .as_ref() + .cloned() + .ok_or_else(|| zerror!("session closed").into()) + } + #[inline] fn get_local_res(&self, id: &ExprId) -> Option<&Resource> { self.local_resources.get(id) @@ -359,124 +366,6 @@ impl Resource { } } -#[derive(Clone)] -pub enum SessionRef<'a> { - Borrow(&'a Session), - Shared(Arc), -} - -impl<'s, 'a> SessionDeclarations<'s, 'a> for SessionRef<'a> { - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SubscriberBuilder { - session: self.clone(), - key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), - #[cfg(feature = "unstable")] - reliability: Reliability::DEFAULT, - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - QueryableBuilder { - session: self.clone(), - key_expr: key_expr.try_into().map_err(Into::into), - complete: false, - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublisherBuilder { - session: self.clone(), - key_expr: key_expr.try_into().map_err(Into::into), - encoding: Encoding::default(), - congestion_control: CongestionControl::DEFAULT, - priority: Priority::DEFAULT, - is_express: false, - #[cfg(feature = "unstable")] - reliability: Reliability::DEFAULT, - destination: Locality::default(), - } - } - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'a> { - Liveliness { - session: self.clone(), - } - } - fn info(&'s self) -> SessionInfo<'a> { - SessionInfo { - session: self.clone(), - } - } -} - -impl Deref for SessionRef<'_> { - type Target = Session; - - fn deref(&self) -> &Self::Target { - match self { - SessionRef::Borrow(b) => b, - SessionRef::Shared(s) => s, - } - } -} - -impl fmt::Debug for SessionRef<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SessionRef::Borrow(b) => Session::fmt(b, f), - SessionRef::Shared(s) => Session::fmt(s, f), - } - } -} - -#[derive(Debug, Clone)] -pub(crate) enum MaybeWeakSessionRef<'a> { - Borrow(&'a Session), - Arc(Arc), - Weak(Weak), -} - -impl<'a> MaybeWeakSessionRef<'a> { - pub(crate) fn new(session: SessionRef<'a>, downgrade: bool) -> Self { - match session { - SessionRef::Borrow(s) => Self::Borrow(s), - SessionRef::Shared(s) if downgrade => Self::Weak(Arc::downgrade(&s)), - SessionRef::Shared(s) => Self::Arc(s), - } - } - - pub(crate) fn upgrade(&self) -> Option> { - match self { - Self::Borrow(s) => Some(SessionRef::Borrow(s)), - Self::Arc(s) => Some(SessionRef::Shared(s.clone())), - Self::Weak(s) => s.upgrade().map(SessionRef::Shared), - } - } -} - /// A trait implemented by types that can be undeclared. pub trait UndeclarableSealed { type Undeclaration: Resolve> + Send; @@ -502,113 +391,60 @@ pub trait Undeclarable: UndeclarableSealed {} impl Undeclarable for T where T: UndeclarableSealed {} -/// A zenoh session. -/// -pub struct Session { +pub(crate) struct SessionInner { pub(crate) runtime: Runtime, - pub(crate) state: Arc>, + pub(crate) state: RwLock, pub(crate) id: u16, - close_on_drop: bool, owns_runtime: bool, task_controller: TaskController, } +impl fmt::Debug for SessionInner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Session") + .field("id", &self.runtime.zid()) + .finish() + } +} + +/// A zenoh session. +/// +#[derive(Clone)] +pub struct Session(pub(crate) Arc); + static SESSION_ID_COUNTER: AtomicU16 = AtomicU16::new(0); impl Session { pub(crate) fn init( runtime: Runtime, aggregated_subscribers: Vec, aggregated_publishers: Vec, + owns_runtime: bool, ) -> impl Resolve { ResolveClosure::new(move || { let router = runtime.router(); - let state = Arc::new(RwLock::new(SessionState::new( + let state = RwLock::new(SessionState::new( aggregated_subscribers, aggregated_publishers, - ))); - let session = Session { + )); + let session = Arc::new(SessionInner { runtime: runtime.clone(), - state: state.clone(), + state, id: SESSION_ID_COUNTER.fetch_add(1, Ordering::SeqCst), - close_on_drop: true, - owns_runtime: false, + owns_runtime, task_controller: TaskController::default(), - }; + }); - runtime.new_handler(Arc::new(admin::Handler::new(session.clone()))); + runtime.new_handler(Arc::new(admin::Handler::new(Arc::downgrade(&session)))); - let primitives = Some(router.new_primitives(Arc::new(session.clone()))); - zwrite!(state).primitives = primitives; + let primitives = Some(router.new_primitives(Arc::new(Arc::downgrade(&session)))); + zwrite!(session.state).primitives = primitives; admin::init(&session); - session + Session(session) }) } - /// Consumes the given `Session`, returning a thread-safe reference-counting - /// pointer to it (`Arc`). This is equivalent to `Arc::new(session)`. - /// - /// This is useful to share ownership of the `Session` between several threads - /// and tasks. It also allows to create [`Subscriber`](crate::pubsub::Subscriber) and - /// [`Queryable`](crate::query::Queryable) with static lifetime that can be moved to several - /// threads and tasks - /// - /// Note: the given zenoh `Session` will be closed when the last reference to - /// it is dropped. - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - pub fn into_arc(self) -> Arc { - Arc::new(self) - } - - /// Consumes and leaks the given `Session`, returning a `'static` mutable - /// reference to it. The given `Session` will live for the remainder of - /// the program's life. Dropping the returned reference will cause a memory - /// leak. - /// - /// This is useful to move entities (like [`Subscriber`](crate::pubsub::Subscriber)) which - /// lifetimes are bound to the session lifetime in several threads or tasks. - /// - /// Note: the given zenoh `Session` cannot be closed any more. At process - /// termination the zenoh session will terminate abruptly. If possible prefer - /// using [`Session::into_arc()`](Session::into_arc). - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::Session::leak(zenoh::open(zenoh::config::peer()).await.unwrap()); - /// let subscriber = session.declare_subscriber("key/expression").await.unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - pub fn leak(s: Self) -> &'static mut Self { - Box::leak(Box::new(s)) - } - /// Returns the identifier of the current session. `zid()` is a convenient shortcut. /// See [`Session::info()`](`Session::info()`) and [`SessionInfo::zid()`](`SessionInfo::zid()`) for more details. pub fn zid(&self) -> ZenohId { @@ -616,7 +452,7 @@ impl Session { } pub fn hlc(&self) -> Option<&HLC> { - self.runtime.hlc() + self.0.runtime.hlc() } /// Close the zenoh [`Session`](Session). @@ -634,23 +470,8 @@ impl Session { /// session.close().await.unwrap(); /// # } /// ``` - pub fn close(mut self) -> impl Resolve> { - ResolveFuture::new(async move { - trace!("close()"); - // set the flag first to avoid double panic if this function panic - self.close_on_drop = false; - self.task_controller.terminate_all(Duration::from_secs(10)); - if self.owns_runtime { - self.runtime.close().await?; - } - let mut state = zwrite!(self.state); - // clean up to break cyclic references from self.state to itself - let primitives = state.primitives.take(); - state.queryables.clear(); - drop(state); - primitives.as_ref().unwrap().send_close(); - Ok(()) - }) + pub fn close(&self) -> impl Resolve> + '_ { + self.0.close() } pub fn undeclare<'a, T>(&'a self, decl: T) -> impl Resolve> + 'a @@ -690,7 +511,7 @@ impl Session { /// # } /// ``` pub fn config(&self) -> &Notifier { - self.runtime.config() + self.0.runtime.config() } /// Get a new Timestamp from a Zenoh session [`Session`](Session). @@ -715,49 +536,175 @@ impl Session { // Called in the case that the runtime is not initialized with an hlc // UNIX_EPOCH is Returns a Timespec::zero(), Unwrap Should be permissable here let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().into(); - Timestamp::new(now, self.runtime.zid().into()) + Timestamp::new(now, self.0.runtime.zid().into()) } } } } -impl<'a> SessionDeclarations<'a, 'a> for Session { - fn info(&self) -> SessionInfo { - SessionRef::Borrow(self).info() +impl Session { + /// Get information about the zenoh [`Session`](Session). + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// use zenoh::prelude::*; + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let info = session.info(); + /// # } + /// ``` + pub fn info(&self) -> SessionInfo { + SessionInfo { + runtime: self.0.runtime.clone(), + } } - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The resourkey expression to subscribe to + /// + /// # Examples + /// ```no_run + /// # #[tokio::main] + /// # async fn main() { + /// use zenoh::prelude::*; + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let subscriber = session.declare_subscriber("key/expression") + /// .await + /// .unwrap(); + /// tokio::task::spawn(async move { + /// while let Ok(sample) = subscriber.recv_async().await { + /// println!("Received: {:?}", sample); + /// } + /// }).await; + /// # } + /// ``` + pub fn declare_subscriber<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> + ) -> SubscriberBuilder<'_, 'b, DefaultHandler> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_subscriber(key_expr) + SubscriberBuilder { + session: self, + key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), + #[cfg(feature = "unstable")] + reliability: Reliability::DEFAULT, + origin: Locality::default(), + handler: DefaultHandler::default(), + } } - fn declare_queryable<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The key expression matching the queries the + /// [`Queryable`](crate::query::Queryable) will reply to + /// + /// # Examples + /// ```no_run + /// # #[tokio::main] + /// # async fn main() { + /// use zenoh::prelude::*; + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let queryable = session.declare_queryable("key/expression") + /// .await + /// .unwrap(); + /// tokio::task::spawn(async move { + /// while let Ok(query) = queryable.recv_async().await { + /// query.reply( + /// "key/expression", + /// "value", + /// ).await.unwrap(); + /// } + /// }).await; + /// # } + /// ``` + pub fn declare_queryable<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> + ) -> QueryableBuilder<'_, 'b, DefaultHandler> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_queryable(key_expr) + QueryableBuilder { + session: self, + key_expr: key_expr.try_into().map_err(Into::into), + complete: false, + origin: Locality::default(), + handler: DefaultHandler::default(), + } } - fn declare_publisher<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The key expression matching resources to write + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// use zenoh::prelude::*; + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let publisher = session.declare_publisher("key/expression") + /// .await + /// .unwrap(); + /// publisher.put("value").await.unwrap(); + /// # } + /// ``` + pub fn declare_publisher<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> + ) -> PublisherBuilder<'_, 'b> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_publisher(key_expr) + PublisherBuilder { + session: self, + key_expr: key_expr.try_into().map_err(Into::into), + encoding: Encoding::default(), + congestion_control: CongestionControl::DEFAULT, + priority: Priority::DEFAULT, + is_express: false, + #[cfg(feature = "unstable")] + reliability: Reliability::DEFAULT, + destination: Locality::default(), + } } + + /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// use zenoh::prelude::*; + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let liveliness = session + /// .liveliness() + /// .declare_token("key/expression") + /// .await + /// .unwrap(); + /// # } + /// ``` #[zenoh_macros::unstable] - fn liveliness(&'a self) -> Liveliness { - SessionRef::Borrow(self).liveliness() + pub fn liveliness(&self) -> Liveliness<'_> { + Liveliness { session: self } } } @@ -786,11 +733,11 @@ impl Session { >>::Error: Into, { let key_expr: ZResult = key_expr.try_into().map_err(Into::into); - let sid = self.id; + let sid = self.0.id; ResolveClosure::new(move || { let key_expr: KeyExpr = key_expr?; let prefix_len = key_expr.len() as u32; - let expr_id = self.declare_prefix(key_expr.as_str()).wait(); + let expr_id = self.0.declare_prefix(key_expr.as_str()).wait()?; let key_expr = match key_expr.0 { KeyExprInner::Borrowed(key_expr) | KeyExprInner::BorrowedWire { key_expr, .. } => { KeyExpr(KeyExprInner::BorrowedWire { @@ -926,7 +873,7 @@ impl Session { { let selector = selector.try_into().map_err(Into::into); let timeout = { - let conf = self.runtime.config().lock(); + let conf = self.0.runtime.config().lock(); Duration::from_millis(unwrap_or_default!(conf.queries_default_timeout())) }; let qos: QoS = request::ext::QoSType::REQUEST.into(); @@ -948,17 +895,6 @@ impl Session { } impl Session { - pub(crate) fn clone(&self) -> Self { - Self { - runtime: self.runtime.clone(), - state: self.state.clone(), - id: self.id, - close_on_drop: false, - owns_runtime: self.owns_runtime, - task_controller: self.task_controller.clone(), - } - } - #[allow(clippy::new_ret_no_self)] pub(super) fn new( config: Config, @@ -976,28 +912,47 @@ impl Session { } let mut runtime = runtime.build().await?; - let mut session = Self::init( + let session = Self::init( runtime.clone(), aggregated_subscribers, aggregated_publishers, + true, ) .await; - session.owns_runtime = true; runtime.start().await?; Ok(session) }) } - - pub(crate) fn declare_prefix<'a>(&'a self, prefix: &'a str) -> impl Resolve + 'a { +} +impl SessionInner { + fn close(&self) -> impl Resolve> + '_ { + ResolveFuture::new(async move { + let Some(primitives) = zwrite!(self.state).primitives.take() else { + return Ok(()); + }; + trace!("close()"); + self.task_controller.terminate_all(Duration::from_secs(10)); + if self.owns_runtime { + self.runtime.close().await?; + } + primitives.send_close(); + Ok(()) + }) + } + pub(crate) fn declare_prefix<'a>( + &'a self, + prefix: &'a str, + ) -> impl Resolve> + 'a { ResolveClosure::new(move || { trace!("declare_prefix({:?})", prefix); let mut state = zwrite!(self.state); + let primitives = state.primitives()?; match state .local_resources .iter() .find(|(_expr_id, res)| res.name() == prefix) { - Some((expr_id, _res)) => *expr_id, + Some((expr_id, _res)) => Ok(*expr_id), None => { let expr_id = state.expr_id_counter.fetch_add(1, Ordering::SeqCst); let mut res = Resource::new(Box::from(prefix)); @@ -1014,7 +969,6 @@ impl Session { } } state.local_resources.insert(expr_id, res); - let primitives = state.primitives.as_ref().unwrap().clone(); drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1030,7 +984,7 @@ impl Session { }, }), }); - expr_id + Ok(expr_id) } } }) @@ -1087,7 +1041,7 @@ impl Session { state.publishers.insert(id, pub_state); if let Some(res) = declared_pub { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { id, @@ -1112,7 +1066,7 @@ impl Session { if !state.publishers.values().any(|p| { p.destination != Locality::SessionLocal && p.remote_id == pub_state.remote_id }) { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { id: pub_state.remote_id, @@ -1132,7 +1086,7 @@ impl Session { } pub(crate) fn declare_subscriber_inner( - &self, + self: &Arc, key_expr: &KeyExpr, origin: Locality, callback: Callback<'static, Sample>, @@ -1216,7 +1170,7 @@ impl Session { } if let Some(key_expr) = declared_sub { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); // If key_expr is a pure Expr, remap it to optimal Rid or RidWithSuffix // let key_expr = if !key_expr.is_optimized(self) { @@ -1263,7 +1217,11 @@ impl Session { Ok(sub_state) } - pub(crate) fn undeclare_subscriber_inner(&self, sid: Id, kind: SubscriberKind) -> ZResult<()> { + pub(crate) fn undeclare_subscriber_inner( + self: &Arc, + sid: Id, + kind: SubscriberKind, + ) -> ZResult<()> { let mut state = zwrite!(self.state); if let Some(sub_state) = state.subscribers_mut(kind).remove(&sid) { trace!("undeclare_subscriber({:?})", sub_state); @@ -1290,7 +1248,7 @@ impl Session { if !state.subscribers(kind).values().any(|s| { s.origin != Locality::SessionLocal && s.remote_id == sub_state.remote_id }) { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1313,7 +1271,7 @@ impl Session { } else { #[cfg(feature = "unstable")] if kind == SubscriberKind::LivelinessSubscriber { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { @@ -1355,7 +1313,7 @@ impl Session { state.queryables.insert(id, qable_state.clone()); if origin != Locality::SessionLocal { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); let qabl_info = QueryableInfoType { complete, @@ -1381,7 +1339,7 @@ impl Session { if let Some(qable_state) = state.queryables.remove(&qid) { trace!("undeclare_queryable({:?})", qable_state); if qable_state.origin != Locality::SessionLocal { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1416,7 +1374,7 @@ impl Session { }); state.tokens.insert(tok_state.id, tok_state.clone()); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1478,7 +1436,7 @@ impl Session { } } - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { @@ -1503,7 +1461,7 @@ impl Session { let key_expr = &tok_state.key_expr; let twin_tok = state.tokens.values().any(|s| s.key_expr == *key_expr); if !twin_tok { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1594,7 +1552,7 @@ impl Session { } #[zenoh_macros::unstable] - pub(crate) fn update_status_up(&self, state: &SessionState, key_expr: &KeyExpr) { + pub(crate) fn update_status_up(self: &Arc, state: &SessionState, key_expr: &KeyExpr) { for msub in state.matching_listeners.values() { if key_expr.intersects(&msub.key_expr) { // Cannot hold session lock when calling tables (matching_status()) @@ -1632,7 +1590,7 @@ impl Session { } #[zenoh_macros::unstable] - pub(crate) fn update_status_down(&self, state: &SessionState, key_expr: &KeyExpr) { + pub(crate) fn update_status_down(self: &Arc, state: &SessionState, key_expr: &KeyExpr) { for msub in state.matching_listeners.values() { if key_expr.intersects(&msub.key_expr) { // Cannot hold session lock when calling tables (matching_status()) @@ -1760,7 +1718,7 @@ impl Session { #[allow(clippy::too_many_arguments)] pub(crate) fn query( - &self, + self: &Arc, key_expr: &KeyExpr<'_>, parameters: &Parameters<'_>, target: QueryTarget, @@ -1795,13 +1753,13 @@ impl Session { let token = self.task_controller.get_cancellation_token(); self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let state = self.state.clone(); + let session = self.clone(); #[cfg(feature = "unstable")] let zid = self.runtime.zid(); async move { tokio::select! { _ = tokio::time::sleep(timeout) => { - let mut state = zwrite!(state); + let mut state = zwrite!(session.state); if let Some(query) = state.queries.remove(&qid) { std::mem::drop(state); tracing::debug!("Timeout on query {}! Send error and close.", qid); @@ -1836,7 +1794,7 @@ impl Session { }, ); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); if destination != Locality::SessionLocal { @@ -1890,7 +1848,7 @@ impl Session { #[cfg(feature = "unstable")] pub(crate) fn liveliness_query( - &self, + self: &Arc, key_expr: &KeyExpr<'_>, timeout: Duration, callback: Callback<'static, Reply>, @@ -1901,12 +1859,12 @@ impl Session { let token = self.task_controller.get_cancellation_token(); self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let state = self.state.clone(); + let session = self.clone(); let zid = self.runtime.zid(); async move { tokio::select! { _ = tokio::time::sleep(timeout) => { - let mut state = zwrite!(state); + let mut state = zwrite!(session.state); if let Some(query) = state.liveliness_queries.remove(&id) { std::mem::drop(state); tracing::debug!("Timeout on liveliness query {}! Send error and close.", id); @@ -1928,266 +1886,115 @@ impl Session { .liveliness_queries .insert(id, LivelinessQueryState { callback }); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); - primitives.send_interest(Interest { - id, - mode: InterestMode::Current, - options: InterestOptions::KEYEXPRS + InterestOptions::TOKENS, - wire_expr: Some(wexpr.clone()), - ext_qos: request::ext::QoSType::DEFAULT, - ext_tstamp: None, - ext_nodeid: request::ext::NodeIdType::DEFAULT, - }); - - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - pub(crate) fn handle_query( - &self, - local: bool, - key_expr: &WireExpr, - parameters: &str, - qid: RequestId, - _target: TargetType, - _consolidation: Consolidation, - body: Option, - attachment: Option, - ) { - let (primitives, key_expr, queryables) = { - let state = zread!(self.state); - match state.wireexpr_to_keyexpr(key_expr, local) { - Ok(key_expr) => { - let queryables = state - .queryables - .iter() - .filter( - |(_, queryable)| - (queryable.origin == Locality::Any - || (local == (queryable.origin == Locality::SessionLocal))) - && - match state.local_wireexpr_to_expr(&queryable.key_expr) { - Ok(qablname) => { - qablname.intersects(&key_expr) - } - Err(err) => { - error!( - "{}. Internal error (queryable key_expr to key_expr failed).", - err - ); - false - } - } - ) - .map(|(id, qable)| (*id, qable.callback.clone())) - .collect::)>>(); - ( - state.primitives.as_ref().unwrap().clone(), - key_expr.into_owned(), - queryables, - ) - } - Err(err) => { - error!("Received Query for unknown key_expr: {}", err); - return; - } - } - }; - - let zid = self.runtime.zid(); - - let query_inner = Arc::new(QueryInner { - key_expr, - parameters: parameters.to_owned().into(), - qid, - zid: zid.into(), - primitives: if local { - Arc::new(self.clone()) - } else { - primitives - }, - }); - for (eid, callback) in queryables { - callback(Query { - inner: query_inner.clone(), - eid, - value: body.as_ref().map(|b| Value { - payload: b.payload.clone().into(), - encoding: b.encoding.clone().into(), - }), - attachment: attachment.clone(), - }); - } - } -} - -impl<'s> SessionDeclarations<'s, 'static> for Arc { - /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The resourkey expression to subscribe to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'static, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SubscriberBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - #[cfg(feature = "unstable")] - reliability: Reliability::DEFAULT, - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - - /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching the queries the - /// [`Queryable`](crate::query::Queryable) will reply to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let queryable = session.declare_queryable("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(query) = queryable.recv_async().await { - /// query.reply( - /// "key/expression", - /// "value", - /// ).await.unwrap(); - /// } - /// }).await; - /// # } - /// ``` - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'static, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - QueryableBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - complete: false, - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } + primitives.send_interest(Interest { + id, + mode: InterestMode::Current, + options: InterestOptions::KEYEXPRS + InterestOptions::TOKENS, + wire_expr: Some(wexpr.clone()), + ext_qos: request::ext::QoSType::DEFAULT, + ext_tstamp: None, + ext_nodeid: request::ext::NodeIdType::DEFAULT, + }); - /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching resources to write - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression") - /// .await - /// .unwrap(); - /// publisher.put("value").await.unwrap(); - /// # } - /// ``` - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'static, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublisherBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - encoding: Encoding::default(), - congestion_control: CongestionControl::DEFAULT, - priority: Priority::DEFAULT, - is_express: false, - #[cfg(feature = "unstable")] - reliability: Reliability::DEFAULT, - destination: Locality::default(), - } + Ok(()) } - /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let liveliness = session - /// .liveliness() - /// .declare_token("key/expression") - /// .await - /// .unwrap(); - /// # } - /// ``` - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'static> { - Liveliness { - session: SessionRef::Shared(self.clone()), - } - } + #[allow(clippy::too_many_arguments)] + pub(crate) fn handle_query( + self: &Arc, + local: bool, + key_expr: &WireExpr, + parameters: &str, + qid: RequestId, + _target: TargetType, + _consolidation: Consolidation, + body: Option, + attachment: Option, + ) { + let (primitives, key_expr, queryables) = { + let state = zread!(self.state); + let Ok(primitives) = state.primitives() else { + return; + }; + match state.wireexpr_to_keyexpr(key_expr, local) { + Ok(key_expr) => { + let queryables = state + .queryables + .iter() + .filter( + |(_, queryable)| + (queryable.origin == Locality::Any + || (local == (queryable.origin == Locality::SessionLocal))) + && + match state.local_wireexpr_to_expr(&queryable.key_expr) { + Ok(qablname) => { + qablname.intersects(&key_expr) + } + Err(err) => { + error!( + "{}. Internal error (queryable key_expr to key_expr failed).", + err + ); + false + } + } + ) + .map(|(id, qable)| (*id, qable.callback.clone())) + .collect::)>>(); + (primitives, key_expr.into_owned(), queryables) + } + Err(err) => { + error!("Received Query for unknown key_expr: {}", err); + return; + } + } + }; - fn info(&'s self) -> SessionInfo<'static> { - SessionInfo { - session: SessionRef::Shared(self.clone()), + let zid = self.runtime.zid(); + + let query_inner = Arc::new(QueryInner { + key_expr, + parameters: parameters.to_owned().into(), + qid, + zid: zid.into(), + primitives: if local { + Arc::new(Arc::downgrade(self)) + } else { + primitives + }, + }); + for (eid, callback) in queryables { + callback(Query { + inner: query_inner.clone(), + eid, + value: body.as_ref().map(|b| Value { + payload: b.payload.clone().into(), + encoding: b.encoding.clone().into(), + }), + attachment: attachment.clone(), + }); } } } -impl Primitives for Session { +impl Primitives for Weak { fn send_interest(&self, msg: zenoh_protocol::network::Interest) { + if self.upgrade().is_none() { + return; + } trace!("recv Interest {} {:?}", msg.id, msg.wire_expr); } fn send_declare(&self, msg: zenoh_protocol::network::Declare) { + let Some(session) = self.upgrade() else { + return; + }; match msg.body { zenoh_protocol::network::DeclareBody::DeclareKeyExpr(m) => { trace!("recv DeclareKeyExpr {} {:?}", m.id, m.wire_expr); - let state = &mut zwrite!(self.state); + let state = &mut zwrite!(session.state); match state.remote_key_to_expr(&m.wire_expr) { Ok(key_expr) => { let mut res_node = ResourceNode::new(key_expr.clone().into()); @@ -2219,14 +2026,14 @@ impl Primitives for Session { trace!("recv DeclareSubscriber {} {:?}", m.id, m.wire_expr); #[cfg(feature = "unstable")] { - let mut state = zwrite!(self.state); + let mut state = zwrite!(session.state); match state .wireexpr_to_keyexpr(&m.wire_expr, false) .map(|e| e.into_owned()) { Ok(expr) => { state.remote_subscribers.insert(m.id, expr.clone()); - self.update_status_up(&state, &expr); + session.update_status_up(&state, &expr); } Err(err) => { tracing::error!( @@ -2241,9 +2048,9 @@ impl Primitives for Session { trace!("recv UndeclareSubscriber {:?}", m.id); #[cfg(feature = "unstable")] { - let mut state = zwrite!(self.state); + let mut state = zwrite!(session.state); if let Some(expr) = state.remote_subscribers.remove(&m.id) { - self.update_status_down(&state, &expr); + session.update_status_down(&state, &expr); } else { tracing::error!("Received Undeclare Subscriber for unknown id: {}", m.id); } @@ -2259,7 +2066,7 @@ impl Primitives for Session { trace!("recv DeclareToken {:?}", m.id); #[cfg(feature = "unstable")] { - let mut state = zwrite!(self.state); + let mut state = zwrite!(session.state); match state .wireexpr_to_keyexpr(&m.wire_expr, false) .map(|e| e.into_owned()) @@ -2293,7 +2100,7 @@ impl Primitives for Session { drop(state); - self.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( false, &m.wire_expr, None, @@ -2316,7 +2123,7 @@ impl Primitives for Session { trace!("recv UndeclareToken {:?}", m.id); #[cfg(feature = "unstable")] { - let mut state = zwrite!(self.state); + let mut state = zwrite!(session.state); if let Some(key_expr) = state.remote_tokens.remove(&m.id) { drop(state); @@ -2325,9 +2132,9 @@ impl Primitives for Session { ..Default::default() }; - self.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( false, - &key_expr.to_wire(self), + &key_expr.to_wire(&session), Some(data_info), ZBuf::default(), SubscriberKind::LivelinessSubscriber, @@ -2349,9 +2156,9 @@ impl Primitives for Session { ..Default::default() }; - self.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( false, - &key_expr.to_wire(self), + &key_expr.to_wire(&session), Some(data_info), ZBuf::default(), SubscriberKind::LivelinessSubscriber, @@ -2376,7 +2183,7 @@ impl Primitives for Session { #[cfg(feature = "unstable")] if let Some(interest_id) = msg.interest_id { - let mut state = zwrite!(self.state); + let mut state = zwrite!(session.state); let _ = state.liveliness_queries.remove(&interest_id); } } @@ -2384,6 +2191,9 @@ impl Primitives for Session { } fn send_push(&self, msg: Push, _reliability: Reliability) { + let Some(session) = self.upgrade() else { + return; + }; trace!("recv Push {:?}", msg); match msg.payload { PushBody::Put(m) => { @@ -2395,7 +2205,7 @@ impl Primitives for Session { source_id: m.ext_sinfo.as_ref().map(|i| i.id.into()), source_sn: m.ext_sinfo.as_ref().map(|i| i.sn as u64), }; - self.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( false, &msg.wire_expr, Some(info), @@ -2415,7 +2225,7 @@ impl Primitives for Session { source_id: m.ext_sinfo.as_ref().map(|i| i.id.into()), source_sn: m.ext_sinfo.as_ref().map(|i| i.sn as u64), }; - self.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( false, &msg.wire_expr, Some(info), @@ -2430,9 +2240,12 @@ impl Primitives for Session { } fn send_request(&self, msg: Request) { + let Some(session) = self.upgrade() else { + return; + }; trace!("recv Request {:?}", msg); match msg.payload { - RequestBody::Query(m) => self.handle_query( + RequestBody::Query(m) => session.handle_query( false, &msg.wire_expr, &m.parameters, @@ -2446,10 +2259,13 @@ impl Primitives for Session { } fn send_response(&self, msg: Response) { + let Some(session) = self.upgrade() else { + return; + }; trace!("recv Response {:?}", msg); match msg.payload { ResponseBody::Err(e) => { - let mut state = zwrite!(self.state); + let mut state = zwrite!(session.state); match state.queries.get_mut(&msg.rid) { Some(query) => { let callback = query.callback.clone(); @@ -2471,7 +2287,7 @@ impl Primitives for Session { } } ResponseBody::Reply(m) => { - let mut state = zwrite!(self.state); + let mut state = zwrite!(session.state); let key_expr = match state.remote_key_to_expr(&msg.wire_expr) { Ok(key) => key.into_owned(), Err(e) => { @@ -2645,8 +2461,11 @@ impl Primitives for Session { } fn send_response_final(&self, msg: ResponseFinal) { + let Some(session) = self.upgrade() else { + return; + }; trace!("recv ResponseFinal {:?}", msg); - let mut state = zwrite!(self.state); + let mut state = zwrite!(session.state); match state.queries.get_mut(&msg.rid) { Some(query) => { query.nb_final -= 1; @@ -2668,178 +2487,28 @@ impl Primitives for Session { } fn send_close(&self) { + if self.upgrade().is_none() { + return; + } trace!("recv Close"); } } -impl Drop for Session { +impl Drop for SessionInner { fn drop(&mut self) { - if self.close_on_drop { - let _ = self.clone().close().wait(); + if let Err(error) = self.close().wait() { + tracing::error!(error); } } } impl fmt::Debug for Session { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Session").field("id", &self.zid()).finish() + self.0.fmt(f) } } -/// Functions to create zenoh entities -/// -/// This trait contains functions to create zenoh entities like -/// [`Subscriber`](crate::pubsub::Subscriber), and -/// [`Queryable`](crate::query::Queryable) -/// -/// This trait is implemented by [`Session`](crate::session::Session) itself and -/// by wrappers [`SessionRef`](crate::session::SessionRef) and [`Arc`](std::sync::Arc) -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); -/// let subscriber = session.declare_subscriber("key/expression") -/// .await -/// .unwrap(); -/// tokio::task::spawn(async move { -/// while let Ok(sample) = subscriber.recv_async().await { -/// println!("Received: {:?}", sample); -/// } -/// }).await; -/// # } -/// ``` -pub trait SessionDeclarations<'s, 'a> { - /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The resourkey expression to subscribe to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching the queries the - /// [`Queryable`](crate::query::Queryable) will reply to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let queryable = session.declare_queryable("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(query) = queryable.recv_async().await { - /// query.reply( - /// "key/expression", - /// "value", - /// ).await.unwrap(); - /// } - /// }).await; - /// # } - /// ``` - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching resources to write - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression") - /// .await - /// .unwrap(); - /// publisher.put("value").await.unwrap(); - /// # } - /// ``` - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let liveliness = session - /// .liveliness() - /// .declare_token("key/expression") - /// .await - /// .unwrap(); - /// # } - /// ``` - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'a>; - /// Get information about the zenoh [`Session`](Session). - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); - /// let info = session.info(); - /// # } - /// ``` - fn info(&'s self) -> SessionInfo<'a>; -} - -impl crate::net::primitives::EPrimitives for Session { +impl crate::net::primitives::EPrimitives for Weak { #[inline] fn send_interest(&self, ctx: crate::net::routing::RoutingContext) { (self as &dyn Primitives).send_interest(ctx.msg) @@ -3039,6 +2708,7 @@ impl Wait for InitBuilder { self.runtime, self.aggregated_subscribers, self.aggregated_publishers, + false, ) .wait()) } diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index 5bca8abcfa..1d15f71757 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -17,7 +17,7 @@ use std::{ future::{IntoFuture, Ready}, mem::size_of, ops::{Deref, DerefMut}, - sync::Arc, + sync::{Arc, Weak}, }; use tracing::error; @@ -30,15 +30,18 @@ use { zenoh_protocol::core::EntityGlobalIdProto, }; -use crate::api::{ - handlers::{locked, Callback, DefaultHandler, IntoHandler}, - key_expr::KeyExpr, - sample::{Locality, Sample}, - session::{MaybeWeakSessionRef, SessionRef, UndeclarableSealed}, - Id, -}; #[cfg(feature = "unstable")] use crate::pubsub::Reliability; +use crate::{ + api::{ + handlers::{locked, Callback, DefaultHandler, IntoHandler}, + key_expr::KeyExpr, + sample::{Locality, Sample}, + session::{SessionInner, UndeclarableSealed}, + Id, + }, + Session, +}; pub(crate) struct SubscriberState { pub(crate) id: Id, @@ -58,10 +61,10 @@ impl fmt::Debug for SubscriberState { } #[derive(Debug)] -pub(crate) struct SubscriberInner<'a> { +pub(crate) struct SubscriberInner { #[cfg(feature = "unstable")] pub(crate) session_id: ZenohId, - pub(crate) session: MaybeWeakSessionRef<'a>, + pub(crate) session: Weak, pub(crate) state: Arc, pub(crate) kind: SubscriberKind, // Subscriber is undeclared on drop unless its handler is a ZST, i.e. it is callback-only @@ -85,19 +88,19 @@ pub(crate) struct SubscriberInner<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct SubscriberUndeclaration<'a, Handler>(Subscriber<'a, Handler>); +pub struct SubscriberUndeclaration(Subscriber); -impl Resolvable for SubscriberUndeclaration<'_, Handler> { +impl Resolvable for SubscriberUndeclaration { type To = ZResult<()>; } -impl Wait for SubscriberUndeclaration<'_, Handler> { +impl Wait for SubscriberUndeclaration { fn wait(mut self) -> ::To { self.0.undeclare_impl() } } -impl IntoFuture for SubscriberUndeclaration<'_, Handler> { +impl IntoFuture for SubscriberUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -126,9 +129,9 @@ impl IntoFuture for SubscriberUndeclaration<'_, Handler> { #[derive(Debug)] pub struct SubscriberBuilder<'a, 'b, Handler> { #[cfg(feature = "unstable")] - pub session: SessionRef<'a>, + pub session: &'a Session, #[cfg(not(feature = "unstable"))] - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, #[cfg(feature = "unstable")] pub key_expr: ZResult>, @@ -304,7 +307,7 @@ where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } impl<'a, Handler> Wait for SubscriberBuilder<'a, '_, Handler> @@ -316,8 +319,8 @@ where let key_expr = self.key_expr?; let session = self.session; let (callback, receiver) = self.handler.into_handler(); - let undeclare_on_drop = size_of::() > 0; session + .0 .declare_subscriber_inner( &key_expr, self.origin, @@ -329,19 +332,17 @@ where #[cfg(not(feature = "unstable"))] &SubscriberInfo::default(), ) - .map(|sub_state| { - Subscriber { - inner: SubscriberInner { - #[cfg(feature = "unstable")] - session_id: session.zid(), - session: MaybeWeakSessionRef::new(session, !undeclare_on_drop), - state: sub_state, - kind: SubscriberKind::Subscriber, - // `size_of::() == 0` means callback-only subscriber - undeclare_on_drop, - }, - handler: receiver, - } + .map(|sub_state| Subscriber { + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: Arc::downgrade(&session.0), + state: sub_state, + kind: SubscriberKind::Subscriber, + // `size_of::() == 0` means callback-only subscriber + undeclare_on_drop: size_of::() > 0, + }, + handler: receiver, }) } } @@ -408,12 +409,12 @@ where /// ``` #[non_exhaustive] #[derive(Debug)] -pub struct Subscriber<'a, Handler> { - pub(crate) inner: SubscriberInner<'a>, +pub struct Subscriber { + pub(crate) inner: SubscriberInner, pub(crate) handler: Handler, } -impl<'a, Handler> Subscriber<'a, Handler> { +impl Subscriber { /// Returns the [`EntityGlobalId`] of this Subscriber. /// /// # Examples @@ -473,9 +474,9 @@ impl<'a, Handler> Subscriber<'a, Handler> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> SubscriberUndeclaration<'a, Handler> + pub fn undeclare(self) -> SubscriberUndeclaration where - Handler: Send + 'a, + Handler: Send, { self.undeclare_inner(()) } @@ -492,7 +493,7 @@ impl<'a, Handler> Subscriber<'a, Handler> { } } -impl Drop for Subscriber<'_, Handler> { +impl Drop for Subscriber { fn drop(&mut self) { if self.inner.undeclare_on_drop { if let Err(error) = self.undeclare_impl() { @@ -502,29 +503,29 @@ impl Drop for Subscriber<'_, Handler> { } } -impl<'a, Handler: Send + 'a> UndeclarableSealed<()> for Subscriber<'a, Handler> { - type Undeclaration = SubscriberUndeclaration<'a, Handler>; +impl<'a, Handler: Send + 'a> UndeclarableSealed<()> for Subscriber { + type Undeclaration = SubscriberUndeclaration; fn undeclare_inner(self, _: ()) -> Self::Undeclaration { SubscriberUndeclaration(self) } } -impl Deref for Subscriber<'_, Handler> { +impl Deref for Subscriber { type Target = Handler; fn deref(&self) -> &Self::Target { self.handler() } } -impl DerefMut for Subscriber<'_, Handler> { +impl DerefMut for Subscriber { fn deref_mut(&mut self) -> &mut Self::Target { self.handler_mut() } } /// A [`Subscriber`] that provides data through a `flume` channel. -pub type FlumeSubscriber<'a> = Subscriber<'a, flume::Receiver>; +pub type FlumeSubscriber = Subscriber>; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum SubscriberKind { diff --git a/zenoh/src/lib.rs b/zenoh/src/lib.rs index 1b563bb4e4..aacc52eefa 100644 --- a/zenoh/src/lib.rs +++ b/zenoh/src/lib.rs @@ -191,15 +191,13 @@ pub mod session { pub use zenoh_config::wrappers::{EntityGlobalId, ZenohId}; pub use zenoh_protocol::core::EntityId; - #[zenoh_macros::unstable] - pub use crate::api::session::SessionRef; #[zenoh_macros::internal] pub use crate::api::session::{init, InitBuilder}; pub use crate::api::{ builders::publisher::{SessionDeleteBuilder, SessionPutBuilder}, info::{PeersZenohIdBuilder, RoutersZenohIdBuilder, SessionInfo, ZenohIdBuilder}, query::SessionGetBuilder, - session::{open, OpenBuilder, Session, SessionDeclarations, Undeclarable}, + session::{open, OpenBuilder, Session, Undeclarable}, }; } @@ -238,7 +236,6 @@ pub mod pubsub { #[zenoh_macros::unstable] pub use crate::api::publisher::{ MatchingListener, MatchingListenerBuilder, MatchingListenerUndeclaration, MatchingStatus, - PublisherDeclarations, PublisherRef, }; pub use crate::api::{ builders::publisher::{ diff --git a/zenoh/src/prelude.rs b/zenoh/src/prelude.rs index 373d56c65a..022a2d63cb 100644 --- a/zenoh/src/prelude.rs +++ b/zenoh/src/prelude.rs @@ -25,8 +25,6 @@ //! ``` mod _prelude { - #[zenoh_macros::unstable] - pub use crate::api::publisher::PublisherDeclarations; #[zenoh_macros::unstable] pub use crate::api::selector::ZenohParameters; pub use crate::{ @@ -34,7 +32,7 @@ mod _prelude { builders::sample::{ EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait, TimestampBuilderTrait, }, - session::{SessionDeclarations, Undeclarable}, + session::Undeclarable, }, config::ValidatedMap, Error as ZError, Resolvable, Resolve, Result as ZResult, diff --git a/zenoh/tests/events.rs b/zenoh/tests/events.rs index 11a6e18b53..e3a4d61656 100644 --- a/zenoh/tests/events.rs +++ b/zenoh/tests/events.rs @@ -52,7 +52,6 @@ async fn close_session(session: Session) { #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn zenoh_events() { - use zenoh::prelude::SessionDeclarations; let session = open_session(&["tcp/127.0.0.1:18447"], &[]).await; let zid = session.zid(); let sub1 = diff --git a/zenoh/tests/liveliness.rs b/zenoh/tests/liveliness.rs index 4d964cc1cf..c67a1deb6d 100644 --- a/zenoh/tests/liveliness.rs +++ b/zenoh/tests/liveliness.rs @@ -19,7 +19,7 @@ use zenoh_core::ztimeout; async fn test_liveliness_subscriber_clique() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -83,7 +83,7 @@ async fn test_liveliness_subscriber_clique() { async fn test_liveliness_query_clique() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -140,7 +140,7 @@ async fn test_liveliness_query_clique() { async fn test_liveliness_subscriber_brokered() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; @@ -219,7 +219,7 @@ async fn test_liveliness_subscriber_brokered() { async fn test_liveliness_query_brokered() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -290,7 +290,7 @@ async fn test_liveliness_query_brokered() { async fn test_liveliness_subscriber_local() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; const TIMEOUT: Duration = Duration::from_secs(60); const SLEEP: Duration = Duration::from_secs(1); @@ -333,7 +333,7 @@ async fn test_liveliness_subscriber_local() { async fn test_liveliness_query_local() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; const TIMEOUT: Duration = Duration::from_secs(60); const SLEEP: Duration = Duration::from_secs(1); diff --git a/zenoh/tests/routing.rs b/zenoh/tests/routing.rs index 07971b7853..1023584c70 100644 --- a/zenoh/tests/routing.rs +++ b/zenoh/tests/routing.rs @@ -56,7 +56,7 @@ enum Task { impl Task { async fn run( &self, - session: Arc, + session: Session, remaining_checkpoints: Arc, token: CancellationToken, ) -> Result<()> { @@ -386,7 +386,7 @@ impl Recipe { // In case of client can't connect to some peers/routers loop { if let Ok(session) = ztimeout!(zenoh::open(config.clone())) { - break session.into_arc(); + break session; } else { tokio::time::sleep(Duration::from_secs(1)).await; } @@ -421,7 +421,7 @@ impl Recipe { // node_task_tracker.wait().await; // Close the session once all the task associated with the node are done. - ztimeout!(Arc::try_unwrap(session).unwrap().close())?; + ztimeout!(session.close())?; println!("Node: {} is closed.", &node.name); Result::Ok(()) From 155c92365398ff88b365ea8eb2855ece2db16493 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Tue, 3 Sep 2024 17:39:20 +0200 Subject: [PATCH 30/33] fix: use weak everywhere! --- zenoh/src/api/builders/publisher.rs | 13 +++++++-- zenoh/src/api/info.rs | 2 +- zenoh/src/api/publisher.rs | 43 +++++++++++++++++------------ zenoh/src/api/queryable.rs | 10 +++---- zenoh/src/api/session.rs | 1 + zenoh/src/api/subscriber.rs | 10 +++---- 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index 957bee62f8..f41b46dfbb 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -11,7 +11,10 @@ // Contributors: // ZettaScale Zenoh Team, // -use std::future::{IntoFuture, Ready}; +use std::{ + future::{IntoFuture, Ready}, + sync::Arc, +}; use zenoh_core::{Resolvable, Result as ZResult, Wait}; #[cfg(feature = "unstable")] @@ -328,7 +331,9 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { // internal function for performing the publication fn create_one_shot_publisher(self) -> ZResult> { Ok(Publisher { - session: self.session.clone().0, + #[cfg(feature = "unstable")] + session_id: self.session.0.runtime.zid(), + session: Arc::downgrade(&self.session.0), id: 0, // This is a one shot Publisher key_expr: self.key_expr?, encoding: self.encoding, @@ -387,7 +392,9 @@ impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { .0 .declare_publisher_inner(key_expr.clone(), self.destination)?; Ok(Publisher { - session: self.session.0.clone(), + #[cfg(feature = "unstable")] + session_id: self.session.0.runtime.zid(), + session: Arc::downgrade(&self.session.0), id, key_expr, encoding: self.encoding, diff --git a/zenoh/src/api/info.rs b/zenoh/src/api/info.rs index 88f8dd57b7..0993663996 100644 --- a/zenoh/src/api/info.rs +++ b/zenoh/src/api/info.rs @@ -156,7 +156,7 @@ impl<'a> IntoFuture for PeersZenohIdBuilder<'a> { } } -/// Struct returned by [`Session::info()`](crate::session::SessionDeclarations::info) which allows +/// Struct returned by [`Session::info()`](crate::Session::info) which allows /// to access information about the current zenoh [`Session`](crate::Session). /// /// # Examples diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index 2777b52b8a..03e78be52d 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -17,7 +17,7 @@ use std::{ fmt, future::{IntoFuture, Ready}, pin::Pin, - sync::Arc, + sync::{Arc, Weak}, task::{Context, Poll}, }; @@ -38,6 +38,7 @@ use { }, std::{collections::HashSet, sync::Mutex}, zenoh_config::wrappers::EntityGlobalId, + zenoh_config::ZenohId, zenoh_protocol::core::EntityGlobalIdProto, }; @@ -106,7 +107,9 @@ impl fmt::Debug for PublisherState { /// ``` #[derive(Debug, Clone)] pub struct Publisher<'a> { - pub(crate) session: Arc, + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: Weak, pub(crate) id: Id, pub(crate) key_expr: KeyExpr<'a>, pub(crate) encoding: Encoding, @@ -122,6 +125,12 @@ pub struct Publisher<'a> { } impl<'a> Publisher<'a> { + fn session(&self) -> ZResult> { + self.session + .upgrade() + .ok_or_else(|| zerror!("session closed").into()) + } + /// Returns the [`EntityGlobalId`] of this Publisher. /// /// # Examples @@ -140,7 +149,7 @@ impl<'a> Publisher<'a> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.session.runtime.zid().into(), + zid: self.session_id.into(), eid: self.id, } .into() @@ -247,7 +256,7 @@ impl<'a> Publisher<'a> { #[zenoh_macros::unstable] pub fn matching_status(&self) -> impl Resolve> + '_ { zenoh_core::ResolveFuture::new(async move { - self.session + self.session()? .matching_status(self.key_expr(), self.destination) }) } @@ -303,14 +312,17 @@ impl<'a> Publisher<'a> { fn undeclare_impl(&mut self) -> ZResult<()> { // set the flag first to avoid double panic if this function panic self.undeclare_on_drop = false; + let Ok(session) = self.session() else { + return Ok(()); + }; #[cfg(feature = "unstable")] { let ids: Vec = zlock!(self.matching_listeners).drain().collect(); for id in ids { - self.session.undeclare_matches_listener_inner(id)? + session.undeclare_matches_listener_inner(id)? } } - self.session.undeclare_publisher_inner(self.id) + session.undeclare_publisher_inner(self.id) } } @@ -418,20 +430,17 @@ impl Publisher<'_> { attachment: Option, ) -> ZResult<()> { tracing::trace!("write({:?}, [...])", &self.key_expr); - let primitives = zread!(self.session.state) - .primitives - .as_ref() - .unwrap() - .clone(); + let session = self.session()?; + let primitives = zread!(session.state).primitives()?; let timestamp = if timestamp.is_none() { - self.session.runtime.new_timestamp() + session.runtime.new_timestamp() } else { timestamp }; if self.destination != Locality::SessionLocal { primitives.send_push( Push { - wire_expr: self.key_expr.to_wire(&self.session).to_owned(), + wire_expr: self.key_expr.to_wire(&session).to_owned(), ext_qos: ext::QoSType::new( self.priority.into(), self.congestion_control, @@ -484,9 +493,9 @@ impl Publisher<'_> { )), }; - self.session.execute_subscriber_callbacks( + session.execute_subscriber_callbacks( true, - &self.key_expr.to_wire(&self.session), + &self.key_expr.to_wire(&session), Some(data_info), payload.into(), SubscriberKind::Subscriber, @@ -770,7 +779,7 @@ where let (callback, receiver) = self.handler.into_handler(); let state = self .publisher - .session + .session()? .declare_matches_listener_inner(self.publisher, callback)?; zlock!(self.publisher.matching_listeners).insert(state.id); Ok(MatchingListener { @@ -932,7 +941,7 @@ impl Wait for MatchingListenerUndeclaration<'_> { zlock!(self.subscriber.publisher.matching_listeners).remove(&self.subscriber.state.id); self.subscriber .publisher - .session + .session()? .undeclare_matches_listener_inner(self.subscriber.state.id) } } diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 37a5b6bc21..590f864218 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -736,7 +736,7 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// A queryable that provides data through a [`Handler`](crate::handlers::IntoHandler). /// /// Queryables can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_queryable`](crate::session::SessionDeclarations::declare_queryable) function +/// with the [`declare_queryable`](crate::Session::declare_queryable) function /// and the [`with`](QueryableBuilder::with) function /// of the resulting builder. /// @@ -863,10 +863,10 @@ impl Queryable { fn undeclare_impl(&mut self) -> ZResult<()> { // set the flag first to avoid double panic if this function panic self.inner.undeclare_on_drop = false; - match self.inner.session.upgrade() { - Some(session) => session.close_queryable(self.inner.state.id), - None => Ok(()), - } + let Some(session) = self.inner.session.upgrade() else { + return Ok(()); + }; + session.close_queryable(self.inner.state.id) } } diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index 945a469bff..bdade37b84 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -939,6 +939,7 @@ impl SessionInner { Ok(()) }) } + pub(crate) fn declare_prefix<'a>( &'a self, prefix: &'a str, diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index 1d15f71757..6d3170c39d 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -484,12 +484,10 @@ impl Subscriber { fn undeclare_impl(&mut self) -> ZResult<()> { // set the flag first to avoid double panic if this function panic self.inner.undeclare_on_drop = false; - match self.inner.session.upgrade() { - Some(session) => { - session.undeclare_subscriber_inner(self.inner.state.id, self.inner.kind) - } - None => Ok(()), - } + let Some(session) = self.inner.session.upgrade() else { + return Ok(()); + }; + session.undeclare_subscriber_inner(self.inner.state.id, self.inner.kind) } } From 5dfd6f3bd4ae8b1d10b534b4a1281e44ddbe3de4 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 4 Sep 2024 13:00:25 +0200 Subject: [PATCH 31/33] fix: fix doc --- zenoh/src/api/subscriber.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index 6d3170c39d..8aafb7a8f5 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -363,7 +363,7 @@ where /// A subscriber that provides data through a [`Handler`](crate::handlers::IntoHandler). /// /// Subscribers can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_subscriber`](crate::session::SessionDeclarations::declare_subscriber) function +/// with the [`declare_subscriber`](crate::Session::declare_subscriber) function /// and the [`with`](SubscriberBuilder::with) function /// of the resulting builder. /// From a938c78b7d169923e134fe4d68d3a69c7223454d Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 4 Sep 2024 16:59:39 +0200 Subject: [PATCH 32/33] feat: use pseudo-weak session with the same perf than arc --- .../src/pub_sub/bin/z_pub_sub.rs | 2 +- .../src/queryable_get/bin/z_queryable_get.rs | 1 - zenoh/src/api/admin.rs | 46 ++--- zenoh/src/api/builders/publisher.rs | 12 +- zenoh/src/api/liveliness.rs | 15 +- zenoh/src/api/publisher.rs | 37 ++-- zenoh/src/api/queryable.rs | 13 +- zenoh/src/api/session.rs | 178 +++++++++++------- zenoh/src/api/subscriber.rs | 15 +- 9 files changed, 160 insertions(+), 159 deletions(-) diff --git a/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs b/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs index f3b1dd0efe..ad96d0b2b0 100644 --- a/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs +++ b/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs @@ -13,7 +13,7 @@ // use std::time::Duration; -use zenoh::{config::Config, key_expr::KeyExpr, prelude::*}; +use zenoh::{config::Config, key_expr::KeyExpr}; #[tokio::main] async fn main() { diff --git a/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs b/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs index 8ea7be201b..e82ecba477 100644 --- a/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs +++ b/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs @@ -16,7 +16,6 @@ use std::{convert::TryFrom, time::Duration}; use zenoh::{ config::Config, key_expr::KeyExpr, - prelude::*, query::{QueryTarget, Selector}, }; diff --git a/zenoh/src/api/admin.rs b/zenoh/src/api/admin.rs index 7452431977..060bb78c43 100644 --- a/zenoh/src/api/admin.rs +++ b/zenoh/src/api/admin.rs @@ -14,7 +14,7 @@ use std::{ collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, - sync::{Arc, Weak}, + sync::Arc, }; use zenoh_core::{Result as ZResult, Wait}; @@ -34,7 +34,7 @@ use super::{ sample::{DataInfo, Locality, SampleKind}, subscriber::SubscriberKind, }; -use crate::api::session::SessionInner; +use crate::api::session::WeakSession; lazy_static::lazy_static!( static ref KE_STARSTAR: &'static keyexpr = unsafe { keyexpr::from_str_unchecked("**") }; @@ -44,10 +44,10 @@ lazy_static::lazy_static!( static ref KE_LINK: &'static keyexpr = unsafe { keyexpr::from_str_unchecked("link") }; ); -pub(crate) fn init(session: &Arc) { +pub(crate) fn init(session: WeakSession) { if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { let admin_key = KeyExpr::from(*KE_PREFIX / own_zid / *KE_SESSION / *KE_STARSTAR) - .to_wire(session) + .to_wire(&session) .to_owned(); let _admin_qabl = session.declare_queryable_inner( @@ -55,18 +55,14 @@ pub(crate) fn init(session: &Arc) { true, Locality::SessionLocal, Arc::new({ - let session = Arc::downgrade(session); - move |q| { - if let Some(session) = Weak::upgrade(&session) { - on_admin_query(&session, q) - } - } + let session = session.clone(); + move |q| on_admin_query(&session, q) }), ); } } -pub(crate) fn on_admin_query(session: &SessionInner, query: Query) { +pub(crate) fn on_admin_query(session: &WeakSession, query: Query) { fn reply_peer(own_zid: &keyexpr, query: &Query, peer: TransportPeer) { let zid = peer.zid.to_string(); if let Ok(zid) = keyexpr::new(&zid) { @@ -128,11 +124,11 @@ pub(crate) fn on_admin_query(session: &SessionInner, query: Query) { #[derive(Clone)] pub(crate) struct Handler { - pub(crate) session: Weak, + pub(crate) session: WeakSession, } impl Handler { - pub(crate) fn new(session: Weak) -> Self { + pub(crate) fn new(session: WeakSession) -> Self { Self { session } } } @@ -159,10 +155,7 @@ impl TransportMulticastEventHandler for Handler { &self, peer: zenoh_transport::TransportPeer, ) -> ZResult> { - let Some(session) = Weak::upgrade(&self.session) else { - bail!("session closed"); - }; - if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { + if let Ok(own_zid) = keyexpr::new(&self.session.runtime.zid().to_string()) { if let Ok(zid) = keyexpr::new(&peer.zid.to_string()) { let expr = WireExpr::from( &(*KE_PREFIX / own_zid / *KE_SESSION / *KE_TRANSPORT_UNICAST / zid), @@ -172,7 +165,7 @@ impl TransportMulticastEventHandler for Handler { encoding: Some(Encoding::APPLICATION_JSON), ..Default::default() }; - session.execute_subscriber_callbacks( + self.session.execute_subscriber_callbacks( true, &expr, Some(info), @@ -205,7 +198,7 @@ impl TransportMulticastEventHandler for Handler { pub(crate) struct PeerHandler { pub(crate) expr: WireExpr<'static>, - pub(crate) session: Weak, + pub(crate) session: WeakSession, } impl TransportPeerEventHandler for PeerHandler { @@ -214,16 +207,13 @@ impl TransportPeerEventHandler for PeerHandler { } fn new_link(&self, link: zenoh_link::Link) { - let Some(session) = Weak::upgrade(&self.session) else { - return; - }; let mut s = DefaultHasher::new(); link.hash(&mut s); let info = DataInfo { encoding: Some(Encoding::APPLICATION_JSON), ..Default::default() }; - session.execute_subscriber_callbacks( + self.session.execute_subscriber_callbacks( true, &self .expr @@ -239,16 +229,13 @@ impl TransportPeerEventHandler for PeerHandler { } fn del_link(&self, link: zenoh_link::Link) { - let Some(session) = Weak::upgrade(&self.session) else { - return; - }; let mut s = DefaultHasher::new(); link.hash(&mut s); let info = DataInfo { kind: SampleKind::Delete, ..Default::default() }; - session.execute_subscriber_callbacks( + self.session.execute_subscriber_callbacks( true, &self .expr @@ -266,14 +253,11 @@ impl TransportPeerEventHandler for PeerHandler { fn closing(&self) {} fn closed(&self) { - let Some(session) = Weak::upgrade(&self.session) else { - return; - }; let info = DataInfo { kind: SampleKind::Delete, ..Default::default() }; - session.execute_subscriber_callbacks( + self.session.execute_subscriber_callbacks( true, &self.expr, Some(info), diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index f41b46dfbb..53c32c8a7d 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -11,10 +11,7 @@ // Contributors: // ZettaScale Zenoh Team, // -use std::{ - future::{IntoFuture, Ready}, - sync::Arc, -}; +use std::future::{IntoFuture, Ready}; use zenoh_core::{Resolvable, Result as ZResult, Wait}; #[cfg(feature = "unstable")] @@ -333,7 +330,7 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { Ok(Publisher { #[cfg(feature = "unstable")] session_id: self.session.0.runtime.zid(), - session: Arc::downgrade(&self.session.0), + session: self.session.downgrade(), id: 0, // This is a one shot Publisher key_expr: self.key_expr?, encoding: self.encoding, @@ -394,7 +391,7 @@ impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { Ok(Publisher { #[cfg(feature = "unstable")] session_id: self.session.0.runtime.zid(), - session: Arc::downgrade(&self.session.0), + session: self.session.downgrade(), id, key_expr, encoding: self.encoding, @@ -404,7 +401,8 @@ impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { destination: self.destination, #[cfg(feature = "unstable")] reliability: self.reliability, - #[cfg(feature = "unstable")]matching_listeners: Default::default(), + #[cfg(feature = "unstable")] + matching_listeners: Default::default(), undeclare_on_drop: true, }) } diff --git a/zenoh/src/api/liveliness.rs b/zenoh/src/api/liveliness.rs index 50bcf9da67..ce6a60ca35 100644 --- a/zenoh/src/api/liveliness.rs +++ b/zenoh/src/api/liveliness.rs @@ -16,7 +16,7 @@ use std::{ convert::TryInto, future::{IntoFuture, Ready}, mem::size_of, - sync::{Arc, Weak}, + sync::Arc, time::Duration, }; @@ -33,7 +33,7 @@ use super::{ subscriber::{Subscriber, SubscriberInner}, Id, }; -use crate::api::session::SessionInner; +use crate::api::session::WeakSession; /// A structure with functions to declare a /// [`LivelinessToken`](LivelinessToken), query @@ -258,7 +258,7 @@ impl Wait for LivelinessTokenBuilder<'_, '_> { .0 .declare_liveliness_inner(&key_expr) .map(|tok_state| LivelinessToken { - session: Arc::downgrade(&self.session.0), + session: self.session.downgrade(), state: tok_state, undeclare_on_drop: true, }) @@ -311,7 +311,7 @@ pub(crate) struct LivelinessTokenState { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessToken { - session: Weak, + session: WeakSession, state: Arc, undeclare_on_drop: bool, } @@ -388,10 +388,7 @@ impl LivelinessToken { fn undeclare_impl(&mut self) -> ZResult<()> { // set the flag first to avoid double panic if this function panic self.undeclare_on_drop = false; - match self.session.upgrade() { - Some(session) => session.undeclare_liveliness(self.state.id), - None => Ok(()), - } + self.session.undeclare_liveliness(self.state.id) } } @@ -581,7 +578,7 @@ where inner: SubscriberInner { #[cfg(feature = "unstable")] session_id: session.zid(), - session: Arc::downgrade(&self.session.0), + session: self.session.downgrade(), state: sub_state, kind: SubscriberKind::LivelinessSubscriber, // `size_of::() == 0` means callback-only subscriber diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index 03e78be52d..0ebcc326ae 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -17,7 +17,6 @@ use std::{ fmt, future::{IntoFuture, Ready}, pin::Pin, - sync::{Arc, Weak}, task::{Context, Poll}, }; @@ -36,7 +35,7 @@ use { handlers::{Callback, DefaultHandler, IntoHandler}, sample::SourceInfo, }, - std::{collections::HashSet, sync::Mutex}, + std::{collections::HashSet, sync::Arc, sync::Mutex}, zenoh_config::wrappers::EntityGlobalId, zenoh_config::ZenohId, zenoh_protocol::core::EntityGlobalIdProto, @@ -54,7 +53,7 @@ use super::{ session::UndeclarableSealed, }; use crate::{ - api::{session::SessionInner, subscriber::SubscriberKind, Id}, + api::{session::WeakSession, subscriber::SubscriberKind, Id}, net::primitives::Primitives, }; @@ -109,7 +108,7 @@ impl fmt::Debug for PublisherState { pub struct Publisher<'a> { #[cfg(feature = "unstable")] pub(crate) session_id: ZenohId, - pub(crate) session: Weak, + pub(crate) session: WeakSession, pub(crate) id: Id, pub(crate) key_expr: KeyExpr<'a>, pub(crate) encoding: Encoding, @@ -125,12 +124,6 @@ pub struct Publisher<'a> { } impl<'a> Publisher<'a> { - fn session(&self) -> ZResult> { - self.session - .upgrade() - .ok_or_else(|| zerror!("session closed").into()) - } - /// Returns the [`EntityGlobalId`] of this Publisher. /// /// # Examples @@ -256,7 +249,7 @@ impl<'a> Publisher<'a> { #[zenoh_macros::unstable] pub fn matching_status(&self) -> impl Resolve> + '_ { zenoh_core::ResolveFuture::new(async move { - self.session()? + self.session .matching_status(self.key_expr(), self.destination) }) } @@ -312,17 +305,14 @@ impl<'a> Publisher<'a> { fn undeclare_impl(&mut self) -> ZResult<()> { // set the flag first to avoid double panic if this function panic self.undeclare_on_drop = false; - let Ok(session) = self.session() else { - return Ok(()); - }; #[cfg(feature = "unstable")] { let ids: Vec = zlock!(self.matching_listeners).drain().collect(); for id in ids { - session.undeclare_matches_listener_inner(id)? + self.session.undeclare_matches_listener_inner(id)? } } - session.undeclare_publisher_inner(self.id) + self.session.undeclare_publisher_inner(self.id) } } @@ -430,17 +420,16 @@ impl Publisher<'_> { attachment: Option, ) -> ZResult<()> { tracing::trace!("write({:?}, [...])", &self.key_expr); - let session = self.session()?; - let primitives = zread!(session.state).primitives()?; + let primitives = zread!(self.session.state).primitives()?; let timestamp = if timestamp.is_none() { - session.runtime.new_timestamp() + self.session.runtime.new_timestamp() } else { timestamp }; if self.destination != Locality::SessionLocal { primitives.send_push( Push { - wire_expr: self.key_expr.to_wire(&session).to_owned(), + wire_expr: self.key_expr.to_wire(&self.session).to_owned(), ext_qos: ext::QoSType::new( self.priority.into(), self.congestion_control, @@ -493,9 +482,9 @@ impl Publisher<'_> { )), }; - session.execute_subscriber_callbacks( + self.session.execute_subscriber_callbacks( true, - &self.key_expr.to_wire(&session), + &self.key_expr.to_wire(&self.session), Some(data_info), payload.into(), SubscriberKind::Subscriber, @@ -779,7 +768,7 @@ where let (callback, receiver) = self.handler.into_handler(); let state = self .publisher - .session()? + .session .declare_matches_listener_inner(self.publisher, callback)?; zlock!(self.publisher.matching_listeners).insert(state.id); Ok(MatchingListener { @@ -941,7 +930,7 @@ impl Wait for MatchingListenerUndeclaration<'_> { zlock!(self.subscriber.publisher.matching_listeners).remove(&self.subscriber.state.id); self.subscriber .publisher - .session()? + .session .undeclare_matches_listener_inner(self.subscriber.state.id) } } diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 590f864218..0904fa138e 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -16,7 +16,7 @@ use std::{ future::{IntoFuture, Ready}, mem::size_of, ops::{Deref, DerefMut}, - sync::{Arc, Weak}, + sync::Arc, }; use tracing::error; @@ -50,7 +50,7 @@ use crate::{ publisher::Priority, sample::{Locality, QoSBuilder, Sample, SampleKind}, selector::Selector, - session::{SessionInner, UndeclarableSealed}, + session::{UndeclarableSealed, WeakSession}, value::Value, Id, }, @@ -543,7 +543,7 @@ impl fmt::Debug for QueryableState { pub(crate) struct QueryableInner { #[cfg(feature = "unstable")] pub(crate) session_id: ZenohId, - pub(crate) session: Weak, + pub(crate) session: WeakSession, pub(crate) state: Arc, // Queryable is undeclared on drop unless its handler is a ZST, i.e. it is callback-only pub(crate) undeclare_on_drop: bool, @@ -863,10 +863,7 @@ impl Queryable { fn undeclare_impl(&mut self) -> ZResult<()> { // set the flag first to avoid double panic if this function panic self.inner.undeclare_on_drop = false; - let Some(session) = self.inner.session.upgrade() else { - return Ok(()); - }; - session.close_queryable(self.inner.state.id) + self.inner.session.close_queryable(self.inner.state.id) } } @@ -930,7 +927,7 @@ where inner: QueryableInner { #[cfg(feature = "unstable")] session_id: session.zid(), - session: Arc::downgrade(&self.session.0), + session: self.session.downgrade(), state: qable_state, // `size_of::() == 0` means callback-only queryable undeclare_on_drop: size_of::() > 0, diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index bdade37b84..e2c4beeb30 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -16,9 +16,10 @@ use std::{ convert::TryInto, fmt, future::{IntoFuture, Ready}, + ops::Deref, sync::{ atomic::{AtomicU16, Ordering}, - Arc, RwLock, Weak, + Arc, Mutex, RwLock, }, time::{Duration, SystemTime, UNIX_EPOCH}, }; @@ -392,6 +393,7 @@ pub trait Undeclarable: UndeclarableSealed {} impl Undeclarable for T where T: UndeclarableSealed {} pub(crate) struct SessionInner { + weak_counter: Mutex, pub(crate) runtime: Runtime, pub(crate) state: RwLock, pub(crate) id: u16, @@ -409,9 +411,78 @@ impl fmt::Debug for SessionInner { /// A zenoh session. /// -#[derive(Clone)] pub struct Session(pub(crate) Arc); +impl Session { + pub(crate) fn downgrade(&self) -> WeakSession { + WeakSession::new(&self.0) + } +} + +impl fmt::Debug for Session { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Clone for Session { + fn clone(&self) -> Self { + let _weak = self.0.weak_counter.lock().unwrap(); + Self(self.0.clone()) + } +} + +impl Drop for Session { + fn drop(&mut self) { + let weak = self.0.weak_counter.lock().unwrap(); + if Arc::strong_count(&self.0) == *weak + 1 { + drop(weak); + if let Err(error) = self.close().wait() { + tracing::error!(error) + } + } + } +} + +pub(crate) struct WeakSession(Arc); + +impl WeakSession { + fn new(session: &Arc) -> Self { + let mut weak = session.weak_counter.lock().unwrap(); + *weak += 1; + Self(session.clone()) + } +} + +impl Clone for WeakSession { + fn clone(&self) -> Self { + let mut weak = self.0.weak_counter.lock().unwrap(); + *weak += 1; + Self(self.0.clone()) + } +} + +impl fmt::Debug for WeakSession { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Deref for WeakSession { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Drop for WeakSession { + fn drop(&mut self) { + let mut weak = self.0.weak_counter.lock().unwrap(); + *weak -= 1; + } +} + static SESSION_ID_COUNTER: AtomicU16 = AtomicU16::new(0); impl Session { pub(crate) fn init( @@ -426,22 +497,23 @@ impl Session { aggregated_subscribers, aggregated_publishers, )); - let session = Arc::new(SessionInner { + let session = Session(Arc::new(SessionInner { + weak_counter: Mutex::new(0), runtime: runtime.clone(), state, id: SESSION_ID_COUNTER.fetch_add(1, Ordering::SeqCst), owns_runtime, task_controller: TaskController::default(), - }); + })); - runtime.new_handler(Arc::new(admin::Handler::new(Arc::downgrade(&session)))); + runtime.new_handler(Arc::new(admin::Handler::new(session.downgrade()))); - let primitives = Some(router.new_primitives(Arc::new(Arc::downgrade(&session)))); - zwrite!(session.state).primitives = primitives; + let primitives = Some(router.new_primitives(Arc::new(session.downgrade()))); + zwrite!(session.0.state).primitives = primitives; - admin::init(&session); + admin::init(session.downgrade()); - Session(session) + session }) } @@ -935,6 +1007,7 @@ impl SessionInner { if self.owns_runtime { self.runtime.close().await?; } + zwrite!(self.state).queryables.clear(); primitives.send_close(); Ok(()) }) @@ -1560,7 +1633,7 @@ impl SessionInner { // TODO: check which ZRuntime should be used self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let session = self.clone(); + let session = WeakSession::new(self); let msub = msub.clone(); async move { match msub.current.lock() { @@ -1598,7 +1671,7 @@ impl SessionInner { // TODO: check which ZRuntime should be used self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let session = self.clone(); + let session = WeakSession::new(self); let msub = msub.clone(); async move { match msub.current.lock() { @@ -1754,7 +1827,7 @@ impl SessionInner { let token = self.task_controller.get_cancellation_token(); self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let session = self.clone(); + let session = WeakSession::new(self); #[cfg(feature = "unstable")] let zid = self.runtime.zid(); async move { @@ -1860,7 +1933,7 @@ impl SessionInner { let token = self.task_controller.get_cancellation_token(); self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let session = self.clone(); + let session = WeakSession::new(self); let zid = self.runtime.zid(); async move { tokio::select! { @@ -1962,7 +2035,7 @@ impl SessionInner { qid, zid: zid.into(), primitives: if local { - Arc::new(Arc::downgrade(self)) + Arc::new(WeakSession::new(self)) } else { primitives }, @@ -1981,21 +2054,15 @@ impl SessionInner { } } -impl Primitives for Weak { +impl Primitives for WeakSession { fn send_interest(&self, msg: zenoh_protocol::network::Interest) { - if self.upgrade().is_none() { - return; - } trace!("recv Interest {} {:?}", msg.id, msg.wire_expr); } fn send_declare(&self, msg: zenoh_protocol::network::Declare) { - let Some(session) = self.upgrade() else { - return; - }; match msg.body { zenoh_protocol::network::DeclareBody::DeclareKeyExpr(m) => { trace!("recv DeclareKeyExpr {} {:?}", m.id, m.wire_expr); - let state = &mut zwrite!(session.state); + let state = &mut zwrite!(self.state); match state.remote_key_to_expr(&m.wire_expr) { Ok(key_expr) => { let mut res_node = ResourceNode::new(key_expr.clone().into()); @@ -2027,14 +2094,14 @@ impl Primitives for Weak { trace!("recv DeclareSubscriber {} {:?}", m.id, m.wire_expr); #[cfg(feature = "unstable")] { - let mut state = zwrite!(session.state); + let mut state = zwrite!(self.state); match state .wireexpr_to_keyexpr(&m.wire_expr, false) .map(|e| e.into_owned()) { Ok(expr) => { state.remote_subscribers.insert(m.id, expr.clone()); - session.update_status_up(&state, &expr); + self.update_status_up(&state, &expr); } Err(err) => { tracing::error!( @@ -2049,9 +2116,9 @@ impl Primitives for Weak { trace!("recv UndeclareSubscriber {:?}", m.id); #[cfg(feature = "unstable")] { - let mut state = zwrite!(session.state); + let mut state = zwrite!(self.state); if let Some(expr) = state.remote_subscribers.remove(&m.id) { - session.update_status_down(&state, &expr); + self.update_status_down(&state, &expr); } else { tracing::error!("Received Undeclare Subscriber for unknown id: {}", m.id); } @@ -2067,7 +2134,7 @@ impl Primitives for Weak { trace!("recv DeclareToken {:?}", m.id); #[cfg(feature = "unstable")] { - let mut state = zwrite!(session.state); + let mut state = zwrite!(self.state); match state .wireexpr_to_keyexpr(&m.wire_expr, false) .map(|e| e.into_owned()) @@ -2101,7 +2168,7 @@ impl Primitives for Weak { drop(state); - session.execute_subscriber_callbacks( + self.execute_subscriber_callbacks( false, &m.wire_expr, None, @@ -2124,7 +2191,7 @@ impl Primitives for Weak { trace!("recv UndeclareToken {:?}", m.id); #[cfg(feature = "unstable")] { - let mut state = zwrite!(session.state); + let mut state = zwrite!(self.state); if let Some(key_expr) = state.remote_tokens.remove(&m.id) { drop(state); @@ -2133,9 +2200,9 @@ impl Primitives for Weak { ..Default::default() }; - session.execute_subscriber_callbacks( + self.execute_subscriber_callbacks( false, - &key_expr.to_wire(&session), + &key_expr.to_wire(self), Some(data_info), ZBuf::default(), SubscriberKind::LivelinessSubscriber, @@ -2157,9 +2224,9 @@ impl Primitives for Weak { ..Default::default() }; - session.execute_subscriber_callbacks( + self.execute_subscriber_callbacks( false, - &key_expr.to_wire(&session), + &key_expr.to_wire(self), Some(data_info), ZBuf::default(), SubscriberKind::LivelinessSubscriber, @@ -2184,7 +2251,7 @@ impl Primitives for Weak { #[cfg(feature = "unstable")] if let Some(interest_id) = msg.interest_id { - let mut state = zwrite!(session.state); + let mut state = zwrite!(self.state); let _ = state.liveliness_queries.remove(&interest_id); } } @@ -2192,9 +2259,6 @@ impl Primitives for Weak { } fn send_push(&self, msg: Push, _reliability: Reliability) { - let Some(session) = self.upgrade() else { - return; - }; trace!("recv Push {:?}", msg); match msg.payload { PushBody::Put(m) => { @@ -2206,7 +2270,7 @@ impl Primitives for Weak { source_id: m.ext_sinfo.as_ref().map(|i| i.id.into()), source_sn: m.ext_sinfo.as_ref().map(|i| i.sn as u64), }; - session.execute_subscriber_callbacks( + self.execute_subscriber_callbacks( false, &msg.wire_expr, Some(info), @@ -2226,7 +2290,7 @@ impl Primitives for Weak { source_id: m.ext_sinfo.as_ref().map(|i| i.id.into()), source_sn: m.ext_sinfo.as_ref().map(|i| i.sn as u64), }; - session.execute_subscriber_callbacks( + self.execute_subscriber_callbacks( false, &msg.wire_expr, Some(info), @@ -2241,12 +2305,9 @@ impl Primitives for Weak { } fn send_request(&self, msg: Request) { - let Some(session) = self.upgrade() else { - return; - }; trace!("recv Request {:?}", msg); match msg.payload { - RequestBody::Query(m) => session.handle_query( + RequestBody::Query(m) => self.handle_query( false, &msg.wire_expr, &m.parameters, @@ -2260,13 +2321,10 @@ impl Primitives for Weak { } fn send_response(&self, msg: Response) { - let Some(session) = self.upgrade() else { - return; - }; trace!("recv Response {:?}", msg); match msg.payload { ResponseBody::Err(e) => { - let mut state = zwrite!(session.state); + let mut state = zwrite!(self.state); match state.queries.get_mut(&msg.rid) { Some(query) => { let callback = query.callback.clone(); @@ -2288,7 +2346,7 @@ impl Primitives for Weak { } } ResponseBody::Reply(m) => { - let mut state = zwrite!(session.state); + let mut state = zwrite!(self.state); let key_expr = match state.remote_key_to_expr(&msg.wire_expr) { Ok(key) => key.into_owned(), Err(e) => { @@ -2462,11 +2520,8 @@ impl Primitives for Weak { } fn send_response_final(&self, msg: ResponseFinal) { - let Some(session) = self.upgrade() else { - return; - }; trace!("recv ResponseFinal {:?}", msg); - let mut state = zwrite!(session.state); + let mut state = zwrite!(self.state); match state.queries.get_mut(&msg.rid) { Some(query) => { query.nb_final -= 1; @@ -2488,28 +2543,11 @@ impl Primitives for Weak { } fn send_close(&self) { - if self.upgrade().is_none() { - return; - } trace!("recv Close"); } } -impl Drop for SessionInner { - fn drop(&mut self) { - if let Err(error) = self.close().wait() { - tracing::error!(error); - } - } -} - -impl fmt::Debug for Session { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl crate::net::primitives::EPrimitives for Weak { +impl crate::net::primitives::EPrimitives for WeakSession { #[inline] fn send_interest(&self, ctx: crate::net::routing::RoutingContext) { (self as &dyn Primitives).send_interest(ctx.msg) diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index 8aafb7a8f5..4dd1caba38 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -17,7 +17,7 @@ use std::{ future::{IntoFuture, Ready}, mem::size_of, ops::{Deref, DerefMut}, - sync::{Arc, Weak}, + sync::Arc, }; use tracing::error; @@ -37,7 +37,7 @@ use crate::{ handlers::{locked, Callback, DefaultHandler, IntoHandler}, key_expr::KeyExpr, sample::{Locality, Sample}, - session::{SessionInner, UndeclarableSealed}, + session::{UndeclarableSealed, WeakSession}, Id, }, Session, @@ -64,7 +64,7 @@ impl fmt::Debug for SubscriberState { pub(crate) struct SubscriberInner { #[cfg(feature = "unstable")] pub(crate) session_id: ZenohId, - pub(crate) session: Weak, + pub(crate) session: WeakSession, pub(crate) state: Arc, pub(crate) kind: SubscriberKind, // Subscriber is undeclared on drop unless its handler is a ZST, i.e. it is callback-only @@ -336,7 +336,7 @@ where inner: SubscriberInner { #[cfg(feature = "unstable")] session_id: session.zid(), - session: Arc::downgrade(&session.0), + session: session.downgrade(), state: sub_state, kind: SubscriberKind::Subscriber, // `size_of::() == 0` means callback-only subscriber @@ -484,10 +484,9 @@ impl Subscriber { fn undeclare_impl(&mut self) -> ZResult<()> { // set the flag first to avoid double panic if this function panic self.inner.undeclare_on_drop = false; - let Some(session) = self.inner.session.upgrade() else { - return Ok(()); - }; - session.undeclare_subscriber_inner(self.inner.state.id, self.inner.kind) + self.inner + .session + .undeclare_subscriber_inner(self.inner.state.id, self.inner.kind) } } From 2ef2446440a47be2033f453caa560be6c3ee8e9d Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Thu, 5 Sep 2024 18:25:20 +0200 Subject: [PATCH 33/33] fix: fix resource cleanup --- zenoh/src/api/session.rs | 3 ++- zenoh/src/net/routing/dispatcher/resource.rs | 1 + zenoh/src/net/runtime/mod.rs | 11 ++++------- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index e2c4beeb30..cf6cfd32da 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -1006,9 +1006,10 @@ impl SessionInner { self.task_controller.terminate_all(Duration::from_secs(10)); if self.owns_runtime { self.runtime.close().await?; + } else { + primitives.send_close(); } zwrite!(self.state).queryables.clear(); - primitives.send_close(); Ok(()) }) } diff --git a/zenoh/src/net/routing/dispatcher/resource.rs b/zenoh/src/net/routing/dispatcher/resource.rs index 01ff9b2817..ab84241666 100644 --- a/zenoh/src/net/routing/dispatcher/resource.rs +++ b/zenoh/src/net/routing/dispatcher/resource.rs @@ -341,6 +341,7 @@ impl Resource { r.parent.take(); r.children.clear(); r.nonwild_prefix.take(); + r.context.take(); r.session_ctxs.clear(); } diff --git a/zenoh/src/net/runtime/mod.rs b/zenoh/src/net/runtime/mod.rs index 9abb01b94e..9f56f4f720 100644 --- a/zenoh/src/net/runtime/mod.rs +++ b/zenoh/src/net/runtime/mod.rs @@ -279,13 +279,10 @@ impl Runtime { // the task responsible for resource clean up was aborted earlier than expected. // This should be resolved by identfying correspodning task, and placing // cancellation token manually inside it. - self.router() - .tables - .tables - .write() - .unwrap() - .root_res - .close(); + let router = self.router(); + let mut tables = router.tables.tables.write().unwrap(); + tables.root_res.close(); + tables.faces.clear(); Ok(()) }