Skip to content

Commit aec3bf3

Browse files
committed
Implemented heartbeat subscriber callback.
1 parent 2f3d406 commit aec3bf3

1 file changed

Lines changed: 115 additions & 6 deletions

File tree

src/api/advanced_subscriber.c

Lines changed: 115 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "zenoh-pico/api/constants.h"
2121
#include "zenoh-pico/api/liveliness.h"
2222
#include "zenoh-pico/api/primitives.h"
23+
#include "zenoh-pico/api/serialization.h"
2324
#include "zenoh-pico/utils/query_params.h"
2425
#include "zenoh-pico/utils/string.h"
2526
#include "zenoh-pico/utils/time_range.h"
@@ -929,7 +930,7 @@ void _ze_advanced_subscriber_subscriber_callback(z_loaned_sample_t *sample, void
929930
!_z_uint32__z_sample_sortedmap_is_empty(&state->_pending_samples)) {
930931
char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE];
931932
_z_query_param_range_t range = {._has_start = state->_has_last_delivered,
932-
._start = state->_last_delivered,
933+
._start = state->_has_last_delivered ? state->_last_delivered + 1 : 0,
933934
._has_end = false,
934935
._end = 0};
935936

@@ -1211,10 +1212,118 @@ void _ze_advanced_subscriber_liveliness_drop_handler(void *ctx) {
12111212
}
12121213
}
12131214

1214-
// TODO
12151215
void _ze_advanced_subscriber_heartbeat_callback(z_loaned_sample_t *sample, void *ctx) {
1216-
(void)(ctx);
1217-
(void)(sample);
1216+
if (z_sample_kind(sample) != Z_SAMPLE_KIND_PUT) {
1217+
return;
1218+
}
1219+
1220+
_ze_advanced_subscriber_state_rc_t *rc_states = (_ze_advanced_subscriber_state_rc_t *)ctx;
1221+
if (_Z_RC_IS_NULL(rc_states)) {
1222+
_Z_ERROR("Heartbeat subscriber callback called with NULL state reference");
1223+
return;
1224+
}
1225+
_ze_advanced_subscriber_state_t *states = _Z_RC_IN_VAL(rc_states);
1226+
1227+
const z_loaned_keyexpr_t *ke = z_sample_keyexpr(sample);
1228+
z_entity_global_id_t id = _z_entity_global_id_null();
1229+
// Parse key expression to extract ZID and EID
1230+
if (!_ze_advanced_subscriber_parse_liveliness_keyexpr(ke, &id)) {
1231+
z_view_string_t kestr;
1232+
z_keyexpr_as_view_string(ke, &kestr);
1233+
_Z_WARN("Received malformed heatbeat key expression: '%.*s'\n", (int)z_string_len(z_view_string_loan(&kestr)),
1234+
z_string_data(z_view_string_loan(&kestr)));
1235+
return;
1236+
}
1237+
1238+
const z_loaned_bytes_t *payload = z_sample_payload(sample);
1239+
if (payload == NULL || z_bytes_len(payload) < 4) {
1240+
_Z_WARN("Received heartbeat with invalid payload length: %zu", z_bytes_len(payload));
1241+
return;
1242+
}
1243+
1244+
ze_deserializer_t deserializer = ze_deserializer_from_bytes(payload);
1245+
uint32_t heartbeat_sn;
1246+
if (ze_deserializer_deserialize_uint32(&deserializer, &heartbeat_sn) != _Z_RES_OK) {
1247+
_Z_WARN("Failed to deserialize heartbeat sequence number");
1248+
return;
1249+
}
1250+
if (!ze_deserializer_is_done(&deserializer)) {
1251+
_Z_WARN("Heartbeat payload contains unexpected data after sequence number");
1252+
return;
1253+
}
1254+
1255+
if (_z_mutex_lock(&states->_mutex) != _Z_RES_OK) {
1256+
_Z_ERROR("Failed to lock heartbeat subscriber callback mutex");
1257+
return;
1258+
}
1259+
1260+
_ze_advanced_subscriber_sequenced_state_t *state =
1261+
_z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states, &id);
1262+
if (state == NULL) {
1263+
if (states->_global_pending_queries > 0) {
1264+
_z_mutex_unlock(&states->_mutex);
1265+
_Z_TRACE("Skipping heatbeat due to pending global query");
1266+
return;
1267+
}
1268+
1269+
z_entity_global_id_t *new_id = z_malloc(sizeof(z_entity_global_id_t));
1270+
if (new_id == NULL) {
1271+
_z_mutex_unlock(&states->_mutex);
1272+
_Z_ERROR("Failed to allocate memory for new sequenced state ID");
1273+
return;
1274+
}
1275+
*new_id = id;
1276+
1277+
_ze_advanced_subscriber_sequenced_state_t *new_state =
1278+
z_malloc(sizeof(_ze_advanced_subscriber_sequenced_state_t));
1279+
if (new_state == NULL) {
1280+
_z_mutex_unlock(&states->_mutex);
1281+
_Z_ERROR("Failed to allocate memory for new sequenced state");
1282+
z_free(new_id);
1283+
return;
1284+
}
1285+
z_result_t res =
1286+
_ze_advanced_subscriber_sequenced_state_init(new_state, z_keyexpr_loan(&states->_keyexpr), &id);
1287+
if (res != _Z_RES_OK) {
1288+
_z_mutex_unlock(&states->_mutex);
1289+
_Z_ERROR("Failed to initialize new sequenced state: %i", res);
1290+
z_free(new_id);
1291+
z_free(new_state);
1292+
return;
1293+
}
1294+
state = _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_insert(&states->_sequenced_states,
1295+
new_id, new_state);
1296+
if (state == NULL) {
1297+
_z_mutex_unlock(&states->_mutex);
1298+
_Z_ERROR("Failed to insert new sequenced state into hashmap");
1299+
z_free(new_id);
1300+
z_free(new_state);
1301+
return;
1302+
}
1303+
}
1304+
1305+
if (!state->_has_last_delivered || (heartbeat_sn > state->_last_delivered && state->_pending_queries == 0)) {
1306+
char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE];
1307+
_z_query_param_range_t range = {._has_start = state->_has_last_delivered,
1308+
._start = state->_has_last_delivered ? state->_last_delivered + 1 : 0,
1309+
._has_end = true,
1310+
._end = heartbeat_sn};
1311+
1312+
if (!_ze_advanced_subscriber_populate_query_params(params, sizeof(params), 0, 0, &range)) {
1313+
_z_mutex_unlock(&states->_mutex);
1314+
_Z_ERROR("Failed to prepare query for missing samples");
1315+
return;
1316+
} else {
1317+
state->_pending_queries++;
1318+
if (_ze_advanced_subscriber_sequenced_query(rc_states, ke, params, &id) != _Z_RES_OK) {
1319+
state->_pending_queries--;
1320+
_z_mutex_unlock(&states->_mutex);
1321+
_Z_ERROR("Failed to query for missing samples");
1322+
return;
1323+
}
1324+
}
1325+
}
1326+
_z_mutex_unlock(&states->_mutex);
12181327
}
12191328

12201329
void _ze_advanced_subscriber_heartbeat_drop_handler(void *ctx) {
@@ -1275,7 +1384,7 @@ z_result_t ze_declare_advanced_subscriber(const z_loaned_session_t *zs, ze_owned
12751384
z_keyexpr_drop(z_keyexpr_move(&ke_pub)));
12761385

12771386
// Create Advanced Subscriber state
1278-
_Z_CLEAN_RETURN_IF_ERR(_ze_advanced_subscriber_state_new(&sub->_val._state, zs, callback, keyexpr, options),
1387+
_Z_CLEAN_RETURN_IF_ERR(_ze_advanced_subscriber_state_new(&sub->_val._state, zs, callback, keyexpr, &opt),
12791388
z_keyexpr_drop(z_keyexpr_move(&ke_pub)));
12801389

12811390
// Declare subscriber
@@ -1330,7 +1439,7 @@ z_result_t ze_declare_advanced_subscriber(const z_loaned_session_t *zs, ze_owned
13301439

13311440
_ze_advanced_subscriber_state_rc_t *liveliness_sub_state =
13321441
_ze_advanced_subscriber_state_rc_clone_as_ptr(&sub->_val._state);
1333-
if (_Z_RC_IS_NULL(sub_state)) {
1442+
if (_Z_RC_IS_NULL(liveliness_sub_state)) {
13341443
z_keyexpr_drop(z_keyexpr_move(&ke_pub));
13351444
_ze_advanced_subscriber_drop(&sub->_val);
13361445
_Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);

0 commit comments

Comments
 (0)