|
20 | 20 | #include "zenoh-pico/api/constants.h" |
21 | 21 | #include "zenoh-pico/api/liveliness.h" |
22 | 22 | #include "zenoh-pico/api/primitives.h" |
| 23 | +#include "zenoh-pico/api/serialization.h" |
23 | 24 | #include "zenoh-pico/utils/query_params.h" |
24 | 25 | #include "zenoh-pico/utils/string.h" |
25 | 26 | #include "zenoh-pico/utils/time_range.h" |
@@ -929,7 +930,7 @@ void _ze_advanced_subscriber_subscriber_callback(z_loaned_sample_t *sample, void |
929 | 930 | !_z_uint32__z_sample_sortedmap_is_empty(&state->_pending_samples)) { |
930 | 931 | char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE]; |
931 | 932 | _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, |
933 | 934 | ._has_end = false, |
934 | 935 | ._end = 0}; |
935 | 936 |
|
@@ -1211,10 +1212,118 @@ void _ze_advanced_subscriber_liveliness_drop_handler(void *ctx) { |
1211 | 1212 | } |
1212 | 1213 | } |
1213 | 1214 |
|
1214 | | -// TODO |
1215 | 1215 | 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); |
1218 | 1327 | } |
1219 | 1328 |
|
1220 | 1329 | 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 |
1275 | 1384 | z_keyexpr_drop(z_keyexpr_move(&ke_pub))); |
1276 | 1385 |
|
1277 | 1386 | // 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), |
1279 | 1388 | z_keyexpr_drop(z_keyexpr_move(&ke_pub))); |
1280 | 1389 |
|
1281 | 1390 | // Declare subscriber |
@@ -1330,7 +1439,7 @@ z_result_t ze_declare_advanced_subscriber(const z_loaned_session_t *zs, ze_owned |
1330 | 1439 |
|
1331 | 1440 | _ze_advanced_subscriber_state_rc_t *liveliness_sub_state = |
1332 | 1441 | _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)) { |
1334 | 1443 | z_keyexpr_drop(z_keyexpr_move(&ke_pub)); |
1335 | 1444 | _ze_advanced_subscriber_drop(&sub->_val); |
1336 | 1445 | _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY); |
|
0 commit comments