From d883c017a22abb67abacf19e1f3394f6c0ecb322 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 13 May 2022 14:30:23 +0000 Subject: [PATCH 01/97] first cut --- common/events.h | 158 +++++++++++++++++++++++++++++++++++++++ common/events_common.cpp | 125 +++++++++++++++++++++++++++++++ common/events_common.h | 66 ++++++++++++++++ 3 files changed, 349 insertions(+) create mode 100644 common/events.h create mode 100644 common/events_common.cpp create mode 100644 common/events_common.h diff --git a/common/events.h b/common/events.h new file mode 100644 index 000000000..a841136cf --- /dev/null +++ b/common/events.h @@ -0,0 +1,158 @@ +/* + * Events library + * + * APIs are for publishing & receiving events with source, tag and params along with timestamp. + * + */ + + +class events_base; + +typedef events_base* event_handle_t; + +/* + * Initialize an event publisher instance for an event source. + * + * A single publisher instance is maintained for a source. + * Any duplicate init call for a source will return the same instance. + * + * Choosing cache will help read cached data, during downtime, if any. + * + * NOTE: + * The initialization occurs asynchronously. + * Any event published before init is complete, is blocked until the init + * is complete. Hence recommend, do the init as soon as the process starts. + * + * Input: + * event_source + * The YANG module name for the event source. All events published with the handle + * returned by this call is tagged with this source, transparently. The receiver + * could subscribe with this source as filter. + * Return + * Non NULL handle + * NULL on failure + */ + +event_handle_t events_init_publisher(std::string &event_source); + +/* + * De-init/free the publisher + * + * Input: + * Handle returned from events_init_publisher + * + * Output: + * None + */ +void events_deinit_publisher(event_handle_t &handle); + + +/* + * List of event params + */ +typedef std::map event_params_t; + +/* + * Publish an event + * + * Internally a globally unique sequence number is embedded in every published event, + * The sequence numbers from same publishing instances can be compared + * to see if there any missing events between. + * + * The sequence has two components as run-time-id that distinguishes + * the running instance of a publisher and other a running sequence + * starting from 0, which is local to this runtime-id. + * + * The receiver API keep next last received number for each runtime id + * and use this info to compute missed event count upon next event. + * + * input: + * handle - As obtained from events_init_publisher for a event-source. + * + * event_tag - + * Name of the YANG container that defines this event in the + * event-source module associated with this handle. + * + * YANG path formatted as "< event_source >:< event_tag >" + * e.g. {"sonic-events-bgp:bgp-state": { "ip": "10.10.10.10", ...}} + * + * params - + * Params associated with event; This may or may not contain + * timestamp. In the absence, the timestamp is added, transparently. + * + */ +void event_publish(event_handle_t handle, const std:string &event_tag, + const event_params_t *params=NULL); + + + +typedef std::vector event_subscribe_sources_t; + +/* + * Initialize subscriber. + * Init subscriber, optionally to filter by event-source. + * + * Input: + * use_cache + * When set to true, it will make use of the cache service transparently. + * The cache service caches events during session down time (last deinit to this + * init call). + * + * lst_subscribe_sources_t + * List of subscription sources of interest. + * The source value is the corresponding YANG module name. + * e.g. "sonic-events-bgp " is the source modulr name for bgp. + * + * Return: + * Non NULL handle on success + * NULL on failure + */ +event_handle_t events_init_subscriber(bool use_cache=false, + const event_subscribe_sources_t *sources=NULL); + +/* + * De-init/free the subscriber + * + * Input: + * Handle returned from events_init_subscriber + * + * Output: + * None + */ +void events_deinit_subscriber(event_handle_t &handle); + +/* + * Received event as JSON string as + * < YANG path of schema >: { + * event_params_t + * } + */ +typedef std::string event_str_t; + +/* + * Receive an event. + * A blocking call. + * + * This API maintains an expected sequence number and use the received + * sequence in event to compute missed events count. + * + * input: + * handle - As obtained from events_init_subscriber + * + * output: + * event - Received event. + * + * missed_cnt: + * Count of missed events from this sender, before this event. Sum of + * missed count from all received events will give the total missed. + */ + int missed_cnt; + + * + * return: + * 0 - On success + * -1 - On failure. The handle is not valid. + * + */ +int event_receive(event_handle_t handle, event_str_t &event, int &missed_cnt); + diff --git a/common/events_common.cpp b/common/events_common.cpp new file mode 100644 index 000000000..1e6d79d57 --- /dev/null +++ b/common/events_common.cpp @@ -0,0 +1,125 @@ +#include "events_common.h" +#include +#include +#include + +/* + * defaults for all config entries + */ +#define CFG_VAL map_str_str_t::value_type +map_str_str_t cfg_data = { + CFG_VAL(XSUB_END_KEY, "tcp://127.0.0.1:5570"), + CFG_VAL(XPUB_END_KEY, "tcp://127.0.0.1:5571"), + CFG_VAL(REQ_REP_END_KEY, "tcp://127.0.0.1:5572"), + CFG_VAL(PAIR_END_KEY, "tcp://127.0.0.1:5573"), + CFG_VAL(STATS_UPD_SECS, 5) +}; + +void +_read_init_config() +{ + ifstream fs (INIT_CFG_PATH); + + if (!fs.is_open()) + return; + + stringstream buffer; + buffer << fs.rdbuf(); + + const auto &data = nlohmann::json::parse(buffer.str()); + + const auto it = data.find(EVENTS_KEY); + if (it == data.end()) + return; + + const auto edata = *it; + for (events_json_data_t::iterator itJ = cfg_data.begin(); + itJ != cfg_data.end(); ++itJ) { + auto itE = edata.find(itJ->first); + if (itE != edata.end()) { + itJ->second = *itE; + } + } + + return; +} + +string +get_config(const string key) +{ + static bool init = false; + + if (!init) { + _read_init_config(); + init = true; + } + /* Intentionally crash for non-existing key, as this + * is internal code bug + */ + return cfg_data[key]; +} + +const string +get_timestamp() +{ + std::stringstream ss, sfrac; + + auto timepoint = system_clock::now(); + std::time_t tt = system_clock::to_time_t (timepoint); + struct std::tm * ptm = std::localtime(&tt); + + uint64_t ms = duration_cast(timepoint.time_since_epoch()).count(); + uint64_t sec = duration_cast(timepoint.time_since_epoch()).count(); + uint64_t mfrac = ms - (sec * 1000 * 1000); + + sfrac << mfrac; + + ss << put_time(ptm, "%b %e %H:%M:%S.") << sfrac.str().substr(0, 6) << "Z"; + return ss.str(); +} + + +/* + * Way to serialize map + * boost::archive::text_oarchive could be used to archive any struct/class + * but that class needs some additional support, that declares + * boost::serialization::access as private friend and couple more tweaks + * std::map inherently supports serialization + */ +const string +serialize(const map_str_str_t& data) +{ + std::stringstream ss; + boost::archive::text_oarchive oarch(ss); + oarch << data; + return ss.str(); +} + +void +deserialize(const string& s, map_str_str_t& data) +{ + std::stringstream ss; + ss << s; + boost::archive::text_iarchive iarch(ss); + iarch >> data; + return; +} + + +void +map_to_zmsg(const map_str_str_t& data, zmq_msg_t &msg) +{ + string s = serialize(data); + + zmq_msg_init_size(&msg, s.size()); + strncpy((char *)zmq_msg_data(&msg), s.c_str(), s.size()); +} + + +void +zmsg_to_map(zmq_msg_t &msg, map_str_str_t& data) +{ + string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); + deserialize(s, data); +} + diff --git a/common/events_common.h b/common/events_common.h new file mode 100644 index 000000000..66ad2e7e9 --- /dev/null +++ b/common/events_common.h @@ -0,0 +1,66 @@ +/* + * common APIs used by events code. + */ +#include +#include +#include +#include "string.h" +#include "json.hpp" +#include "zmq.h" +#include + +#include "logger.h" +#include "events.h" + +using namespace std; +using namespace chrono; + +#define ERR_CHECK(res, ...) {\ + if (!(res)) \ + SWSS_LOG_ERROR(__VA_ARGS__); } + +// Some simple definitions +// +typedef map map_str_str_t; + +/* + * Config that can be read from init_cfg + */ +#define INIT_CFG_PATH "/etc/sonic/init_cfg.json" +#define CFG_EVENTS_KEY "events" + +/* configurable entities' keys */ +#define XSUB_END_KEY "xsub_path" +#define XPUB_END_KEY "xpub_path" +#define REQ_REP_END_KEY "req_rep_path" +#define REQ_PAIR_KEY "pair_path" +#define STATS_UPD_SECS "stats_upd_secs" + +/* Provide a key for configurable entity */ +string get_config(const string key); + +const string get_timestamp(); + +/* + * events are published as two part zmq message. + * First part only has the event source, so receivers could + * filter by source. + * + * Second part contains event as defined below. + * + * The callers would only see, event_str_t + */ +typedef struct { + event_str_t event; + uint32_t runtime_id; + uint32_t sequence; +} internal_event_t; + +const string serialize(const map_str_str_t & data); + +void deserialize(const string& s, map_str_str_t & data); + +void map_to_zmsg(const map_str_str_t & data, zmq_msg_t &msg); + +void zmsg_to_map(zmq_msg_t &msg, map_str_str_t & data); + From c223d04d3a9f0c0a4408439f5a04f99effe67e75 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Sat, 14 May 2022 01:33:26 +0000 Subject: [PATCH 02/97] first cut lib code with unit test --- common/Makefile.am | 3 +- common/events.h | 5 +-- common/events_common.cpp | 14 ++++---- common/events_common.h | 5 ++- tests/Makefile.am | 3 +- tests/events_common_ut.cpp | 70 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 tests/events_common_ut.cpp diff --git a/common/Makefile.am b/common/Makefile.am index 4c400556d..6f0fe413c 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -28,6 +28,7 @@ DBGFLAGS = -g -DNDEBUG endif libswsscommon_la_SOURCES = \ + events_common.cpp \ logger.cpp \ redisreply.cpp \ configdb.cpp \ @@ -69,7 +70,7 @@ libswsscommon_la_SOURCES = \ libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS) -libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) +libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization swssloglevel_SOURCES = loglevel.cpp diff --git a/common/events.h b/common/events.h index a841136cf..d5c867709 100644 --- a/common/events.h +++ b/common/events.h @@ -81,7 +81,7 @@ typedef std::map event_params_t; * timestamp. In the absence, the timestamp is added, transparently. * */ -void event_publish(event_handle_t handle, const std:string &event_tag, +void event_publish(event_handle_t handle, const std::string &event_tag, const event_params_t *params=NULL); @@ -145,9 +145,6 @@ typedef std::string event_str_t; * missed_cnt: * Count of missed events from this sender, before this event. Sum of * missed count from all received events will give the total missed. - */ - int missed_cnt; - * * return: * 0 - On success diff --git a/common/events_common.cpp b/common/events_common.cpp index 1e6d79d57..f7ff07e25 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -12,13 +12,13 @@ map_str_str_t cfg_data = { CFG_VAL(XPUB_END_KEY, "tcp://127.0.0.1:5571"), CFG_VAL(REQ_REP_END_KEY, "tcp://127.0.0.1:5572"), CFG_VAL(PAIR_END_KEY, "tcp://127.0.0.1:5573"), - CFG_VAL(STATS_UPD_SECS, 5) + CFG_VAL(STATS_UPD_SECS, "5") }; void -_read_init_config() +read_init_config(const char *init_cfg_file) { - ifstream fs (INIT_CFG_PATH); + ifstream fs (init_cfg_file); if (!fs.is_open()) return; @@ -28,12 +28,12 @@ _read_init_config() const auto &data = nlohmann::json::parse(buffer.str()); - const auto it = data.find(EVENTS_KEY); + const auto it = data.find(CFG_EVENTS_KEY); if (it == data.end()) return; const auto edata = *it; - for (events_json_data_t::iterator itJ = cfg_data.begin(); + for (map_str_str_t::iterator itJ = cfg_data.begin(); itJ != cfg_data.end(); ++itJ) { auto itE = edata.find(itJ->first); if (itE != edata.end()) { @@ -50,7 +50,7 @@ get_config(const string key) static bool init = false; if (!init) { - _read_init_config(); + read_init_config(INIT_CFG_PATH); init = true; } /* Intentionally crash for non-existing key, as this @@ -74,7 +74,7 @@ get_timestamp() sfrac << mfrac; - ss << put_time(ptm, "%b %e %H:%M:%S.") << sfrac.str().substr(0, 6) << "Z"; + ss << put_time(ptm, "%FT%H:%M:%S.") << sfrac.str().substr(0, 6) << "Z"; return ss.str(); } diff --git a/common/events_common.h b/common/events_common.h index 66ad2e7e9..50fd9bf14 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -33,9 +33,12 @@ typedef map map_str_str_t; #define XSUB_END_KEY "xsub_path" #define XPUB_END_KEY "xpub_path" #define REQ_REP_END_KEY "req_rep_path" -#define REQ_PAIR_KEY "pair_path" +#define PAIR_END_KEY "pair_path" #define STATS_UPD_SECS "stats_upd_secs" +/* init config from file */ +void read_init_config(const char *fname); + /* Provide a key for configurable entity */ string get_config(const string key); diff --git a/tests/Makefile.am b/tests/Makefile.am index a84a6df95..8d8161e40 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -35,7 +35,8 @@ tests_SOURCES = redis_ut.cpp \ boolean_ut.cpp \ status_code_util_test.cpp \ saiaclschema_ut.cpp \ - main.cpp + main.cpp \ + events_common_ut.cpp tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) diff --git a/tests/events_common_ut.cpp b/tests/events_common_ut.cpp new file mode 100644 index 000000000..db067df16 --- /dev/null +++ b/tests/events_common_ut.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "common/events_common.h" + +using namespace std; + +const char *test_cfg_data = "{\ +\"events\" : { \ + \"xsub_path\": \"xsub_path\", \ + \"pair_path\": \"pair_path\" \ + }\ +}"; + + +TEST(events_common, get_config) +{ + EXPECT_EQ(string("tcp://127.0.0.1:5570"), get_config(string(XSUB_END_KEY))); + EXPECT_EQ(string("tcp://127.0.0.1:5573"), get_config(string(PAIR_END_KEY))); + EXPECT_EQ(string("5"), get_config(string(STATS_UPD_SECS))); + + ofstream tfile; + const char *tfile_name = "/tmp/init_cfg.json"; + tfile.open (tfile_name); + tfile << test_cfg_data << "\n"; + tfile.close(); + + read_init_config(tfile_name); + + EXPECT_EQ(string(XSUB_END_KEY), get_config(string(XSUB_END_KEY))); + EXPECT_EQ(string(PAIR_END_KEY), get_config(string(PAIR_END_KEY))); + EXPECT_EQ(string("5"), get_config(string(STATS_UPD_SECS))); + + cout << "events_common: get_config succeeded\n"; +} + +TEST(events_common, ts) +{ + string s = get_timestamp(); + + string reg = "^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\.[0-9]{1,6}Z$"; + + cout << s << "\n"; + EXPECT_TRUE(regex_match (s, regex(reg))); +} + +TEST(events_common, msg) +{ + map t = { + { "foo", "bar" }, + { "test", "5" }, + { "hello", "world" } }; + + map t1; + + zmq_msg_t msg; + + map_to_zmsg(t, msg); + + EXPECT_NE(t, t1); + + zmsg_to_map(msg, t1); + + EXPECT_EQ(t, t1); +} + From 7fbdcf15000674c7520b40fb077c13acba3a2fe7 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 17 May 2022 01:47:38 +0000 Subject: [PATCH 03/97] save it just in case, as VM under risk --- common/COMPILE_README | 43 ++++++++ common/events.cpp | 173 ++++++++++++++++++++++++++++++++ common/events.h | 20 +++- common/events_common.h | 20 +--- common/events_pi.h | 163 ++++++++++++++++++++++++++++++ common/events_service.cpp | 125 +++++++++++++++++++++++ common/events_service.h | 202 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 729 insertions(+), 17 deletions(-) create mode 100644 common/COMPILE_README create mode 100644 common/events.cpp create mode 100644 common/events_pi.h create mode 100644 common/events_service.cpp create mode 100644 common/events_service.h diff --git a/common/COMPILE_README b/common/COMPILE_README new file mode 100644 index 000000000..c0a4bd57e --- /dev/null +++ b/common/COMPILE_README @@ -0,0 +1,43 @@ +1) Using ~/source/sonic-buildimage/c_build.sh +2) It uses _upd_cmn.sh to update files +3) On failure, go to ~/source/sonic-buildimage/target/debs/bullseye +4) open libswsscommon_1.0.0_amd64.deb.log + +Get failing command. Run from inside src/sonic-swss-common/common. Interestingly c compilation alone works fine outside slave too. +NOTE: From within slave you can't copy files from another repo as root of slave is at ~/src/sonic-buildimage + +/bin/bash ../libtool --tag=CXX --mode=compile g++ -DHAVE_CONFIG_H -I. -I.. -I .. -g -DNDEBUG -ansi -fPIC -std=c++11 -Wall -Wcast-align -Wcast-qual -Wconversion -Wdisabled-optimization -Werror -Wextra -Wfloat-equal -Wformat=2 -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winvalid-pch -Wlong-long -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wno-aggregate-return -Wno-padded -Wno-switch-enum -Wno-unused-parameter -Wpacked -Wpointer-arith -Wredundant-decls -Wshadow -Wstack-protector -Wstrict-aliasing=3 -Wswitch -Wswitch-default -Wunreachable-code -Wunused -Wvariadic-macros -Wno-write-strings -Wno-missing-format-attribute -Wno-long-long -Wdate-time -D_FORTIFY_SOURCE=2 -g -DNDEBUG -ansi -fPIC -std=c++11 -Wall -Wcast-align -Wcast-qual -Wconversion -Wdisabled-optimization -Werror -Wextra -Wfloat-equal -Wformat=2 -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winvalid-pch -Wlong-long -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wno-aggregate-return -Wno-padded -Wno-switch-enum -Wno-unused-parameter -Wpacked -Wpointer-arith -Wredundant-decls -Wshadow -Wstack-protector -Wstrict-aliasing=3 -Wswitch -Wswitch-default -Wunreachable-code -Wunused -Wvariadic-macros -Wno-write-strings -Wno-missing-format-attribute -Wno-long-long -I/usr/include/libnl3 -g -O2 -ffile-prefix-map=/sonic/src/sonic-swss-common=. -fstack-protector-strong -Wformat -Werror=format-security -c -o libswsscommon_la-events_common.lo `test -f 'events_common.cpp' || echo './'`events_common.cpp:wq + + + + + + +localadmin@c7cbc0ba3b64:/sonic$ cat c_build.sh +#! /bin/bash + +set -x + +./_upd_cmn.sh + +rm -f target/debs/bullseye/libswsscommon* +rm -f target/sonic-broadcom.bin target/sonic-aboot-broadcom.swi +# KEEP_SLAVE_ON=yes SONIC_BUILD_JOBS=7 PASSWORD=password make target/debs/bullseye/libswsscommon_1.0.0_amd64.deb +KEEP_SLAVE_ON=yes make target/debs/bullseye/libswsscommon_1.0.0_amd64.deb +# make target/debs/bullseye/libswsscommon_1.0.0_amd64.deb +#SONIC_BUILD_JOBS=7 PASSWORD=password make target/sonic-broadcom.bin +# SONIC_BUILD_JOBS=7 PASSWORD=password make target/sonic-aboot-broadcom.swi + + +localadmin@c7cbc0ba3b64:/sonic$ cat _upd_cmn.sh +#! /bin/bash + +SRCD="/home/localadmin/source/fork/syslog_telemetry/remanava/sonic-swss-common/common" +DSTD="./src/sonic-swss-common/common" + +for i in Makefile.am events.h events_common.cpp events_common.h +do + echo "copying $i" + cp ${SRCD}/$i ${DSTD}/$i +done +localadmin@c7cbc0ba3b64:/sonic$ diff --git a/common/events.cpp b/common/events.cpp new file mode 100644 index 000000000..d2c9349fe --- /dev/null +++ b/common/events.cpp @@ -0,0 +1,173 @@ +#include "events_pi.h" + +lst_publishers_t EventPublisher::s_publishers = lst_publishers_t(); + +EventPublisher::EventPublisher(const string source) : + m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0), m_init(false) +{ + uuuid_clear(m_runtime_id); + +} + +int EventPublisher::init(const string event_source, int block_ms) +{ + m_zmq_ctx = zmq_ctx_new(); + m_socket = zmq_socket (m_zmq_ctx, ZMQ_PUB); + + int rc = zmq_connect (m_socket, get_config(XSUB_END_KEY)); + RET_ON_ERR(rc == 0, "Publisher fails to connect %s", get_config(XSUB_END_KEY)); + + // REQ socket is connected and a message is sent & received, more to + // ensure PUB socket had enough time to establish connection. + // Any message published before connection establishment is dropped. + // + event_service m_event_svc; + rc = m_event_svc.init_client(block_ms); + RET_ON_ERR (rc == 0, "Failed to init event service"); + + rc = m_event_svc.echo_send("hello"); + RET_ON_ERR (rc == 0, "Failed to echo send in event service"); + + zmq_msg_init_size(&m_zmsg_source, event_source.size()); + memcpy((char *)zmq_msg_data(&m_zmsg_source), event_source, event_source.size()); + + m_event_source(event_source); + + uuid_t id; + uuid_generate(id); + uuid_unparse(id, m_runtime_id); + + m_init = true; +out: + return m_init ? 0 : -1; +} + +EventPublisher::~EventPublisher() +{ + zmq_msg_close(&m_zmsg_source); + zmq_close(m_socket); + zmq_close(m_echo_socket); + zmq_ctx_term(m_zmq_ctx); +} + + +void +EventPublisher::event_publish(const string tag, const event_params_t *params) +{ + zmq_msg_t msg; + + if (m_event_service.is_active()) { + string s; + + /* Failure is no-op; The eventd service my be down + * NOTE: This call atmost blocks for block_ms milliseconds + * as provided in publisher init. + */ + m_event_service.echo_receive(s); + } + + string param_str; + if ((params != NULL) && (param->find(event_ts) != params->end())) { + + param_str = serialize(*params); + } + else { + event_params_t evt_params = *params; + evt_params[event_ts] = get_timestamp(); + param_str = serialize(evt_params); + } + + map_str_str_t event_str = { { m_event_source + ":" + tag, param_str}}; + + ++m_sequence; + internal_event_t event_data; + event_data[EVENT_STR_DATA] = serialize(event_str); + { + stringstream ss; + + ss << m_sequence; + + event_data[EVENT_SEQUENCE] = ss.str(); + } + event_data[EVENT_RUNTIME_ID] = m_runtime_id; + + map_to_zmsg(event_data, msg); + + // Send the message + // First part -- The event-source/pattern + // Second part -- Metadata + // Third part -- Params, if given + // + RET_ON_ERR(zmq_msg_send (&m_zmsg_source, m_socket, ZMQ_SNDMORE) != -1, + "Failed to publish part 1 to %s", XSUB_PATH); + RET_ON_ERR(zmq_msg_send (&msg, m_socket, 0) != -1, + "Failed to publish part 2 to %s", XSUB_PATH); +out: + zmq_msg_close(&msg_metadata); + +} + +event_handle_t +events_init_publisher(const string event_source, int block_millisecs) +{ + event_handle_t ret = NULL; + lst_publishers_t::iterator it = s_publishers.find(event_source); + if (it != s_publishers.end()) { + // Pre-exists + ret = it->second; + } + else { + EventPublisher *p = new EventPublisher(); + + int rc = p->init(event_source, block_millisecs); + + if (rc != 0) { + delete p; + } + else { + ret = p; + s_publishers[key] = ret; + } + } + return ret; +} + +void +events_deinit_publisher(event_handle_t &handle) +{ + lst_publishers_t::iterator it; + EventPublisher *pub = dynamic_cast(&handle); + + for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { + if (it->second == handle) { + break; + } + } + + if (it != s_publishers.end() { + s_publishers.erase(it); + + delete pub; + } + handle = NULL; + +} + +void +event_publish(event_handle_t handle, const string tag, const event_params_t *params) +{ + EventPublisher *pub = dynamic_cast(handle); + + for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { + if (it->second == handle) { + pub->event_publish(tag, params); + break; + } + } +} + + + + + + diff --git a/common/events.h b/common/events.h index d5c867709..c4b0e2589 100644 --- a/common/events.h +++ b/common/events.h @@ -28,12 +28,21 @@ typedef events_base* event_handle_t; * The YANG module name for the event source. All events published with the handle * returned by this call is tagged with this source, transparently. The receiver * could subscribe with this source as filter. + * + * block_millisecs - + * Block either until publisher connects successfully or timeout + * whichever earlier. + * 0 - No blocling. + * -1 - Block until connected. + * N - Count in milli seconds to wait. + * NOTE: The connection is to eventd service, which could be down. * Return * Non NULL handle * NULL on failure */ -event_handle_t events_init_publisher(std::string &event_source); +event_handle_t events_init_publisher(std::string event_source, + int block_millisecs); /* * De-init/free the publisher @@ -52,6 +61,11 @@ void events_deinit_publisher(event_handle_t &handle); */ typedef std::map event_params_t; +/* + * timestamp param name + */ +const string event_ts("timestamp"); + /* * Publish an event * @@ -79,9 +93,11 @@ typedef std::map event_params_t; * params - * Params associated with event; This may or may not contain * timestamp. In the absence, the timestamp is added, transparently. + * The timestamp should be per rfc3339 + * e.g. "2022-08-17T02:39:21.286611Z" * */ -void event_publish(event_handle_t handle, const std::string &event_tag, +void event_publish(event_handle_t handle, const std::string event_tag, const event_params_t *params=NULL); diff --git a/common/events_common.h b/common/events_common.h index 50fd9bf14..5999af007 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -15,6 +15,11 @@ using namespace std; using namespace chrono; +#define RET_ON_ERR(res, ...) {\ + if (!(res)) \ + SWSS_LOG_ERROR(__VA_ARGS__); } + goto out; + #define ERR_CHECK(res, ...) {\ if (!(res)) \ SWSS_LOG_ERROR(__VA_ARGS__); } @@ -44,21 +49,6 @@ string get_config(const string key); const string get_timestamp(); -/* - * events are published as two part zmq message. - * First part only has the event source, so receivers could - * filter by source. - * - * Second part contains event as defined below. - * - * The callers would only see, event_str_t - */ -typedef struct { - event_str_t event; - uint32_t runtime_id; - uint32_t sequence; -} internal_event_t; - const string serialize(const map_str_str_t & data); void deserialize(const string& s, map_str_str_t & data); diff --git a/common/events_pi.h b/common/events_pi.h new file mode 100644 index 000000000..8a7025d4d --- /dev/null +++ b/common/events_pi.h @@ -0,0 +1,163 @@ +/* + * Private header file + * Required to run white box testing via unit tests. + */ +#include +#include +#include +#include +#include "string.h" +#include "json.hpp" +#include "zmq.h" +#include + +#include "logger.h" +#include "events.h" +#include "events_common.h" +#include "events_service.h" + +using namespace std; + +/* + * events are published as two part zmq message. + * First part only has the event source, so receivers could + * filter by source. + * + * Second part contains map of + * _internal_event_t = +{ + { EVENT_STR_DATA, "" }, + { EVENT_RUNTIME_ID, "" }, + { EVENT_SEQUENCE +internal_event_t internal_event_ref = { + { EVENT_STR_DATA, "" }, + { EVENT_RUNTIME_ID, "" }, + { EVENT_SEQUENCE, "" } }; + +typedef struct _internal_event_t { + + _internal_event_t(event_str_t e, uuid_t r, uint32_t s): + event(e), runtime_id(r), sequence(s) {}; + + event_str_t event; + uuid_t runtime_id; + uint32_t sequence; +} internal_event_t; + +/* Base class for publisher & subscriber */ +class events_base +{ + public: + virtual ~events_base() = default; +}; + +/* + * A single instance per sender & source. + * A sender is very likely to use single source only. + * There can be multiple sender processes/threads for a single source. + * + */ + +typedef map< lst_publishers_t; + +class EventPublisher : public events_base { + public: + // Track publishers by source & sender, as missed messages + // is tracked per sender by source + // + static lst_publishers_t s_publishers; + + void *m_zmq_ctx; + void *m_socket; + + event_service m_event_svc; + + /* Event source in msg to be sent as part 1 of multi-part */ + zmq_msg_t m_zmsg_source; + string m_event_source; + + uuid_t m_runtime_id; + uint32_t m_sequence; + + bool m_init; + + EventPublisher(); + + int init(const char *event_source, int block_ms=-1); + + virtual ~EventPublisher(); + + void publish(event_handle_t &handle, const std::string &event_tag, + const event_params_t *params); + +}; + +/* + * Receiver's instance to receive. + * + * An instance could be created as one per consumer, so a slow customer + * would have nearly no impact on others. + * + */ + +class EventSubscriber : public events_base +{ + public: + + void *m_zmq_ctx; + void *m_socket; + + // Indices are tracked per sendefr & source. + // + map m_indices; + + // Cumulative missed count across all subscribed sources. + // + uint64_t m_missed_cnt; + + EventSubscriber(const event_subscribe_sources_t *subs_sources); + + virtual ~EventSubscriber(); + + bool do_receive(map_str_str_t *data); + + bool validate_meta(const map_str_str_t &meta); + + index_data_t update_missed(map_str_str_t &meta); + + void event_receive(event_metadata_t &metadata, event_params_t ¶ms, + unsigned long *missed_count = NULL); +}; + +class EventProxy +{ + public: + void *m_ctx; + void *m_rep; + void *m_frontend; + void *m_backend; + bool m_init_success; + + std::thread m_req_thread, m_proxy_thread; + + EventProxy(); + + ~EventProxy(); + + int run(void); + + void run_cache_service(void); + void run_proxy(void); +}; + +extern EventProxy g_event_proxy; + + + diff --git a/common/events_service.cpp b/common/events_service.cpp new file mode 100644 index 000000000..d2b89a81c --- /dev/null +++ b/common/events_service.cpp @@ -0,0 +1,125 @@ +#include "events_service.h" + + +int +event_service:init_client(int block_ms) +{ + int rc = -1; + + void *sock = zmq_socket (m_zmq_ctx, ZMQ_REQ); + RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REQ socket"); + + rc = zmq_connect (sock, get_config(REQ_REP_END_KEY)); + RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY)); + + // Set read timeout. + // + rc = zmq_setsockopt (sock, ZMQ_RCVTIMEO, &block_ms, sizeof (block_ms)); + RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY)); + + m_socket = sock; +out: + return ret; +} + +int +event_service:init_server() +{ + int rc = -1; + + void *sock = zmq_socket (m_zmq_ctx, ZMQ_REP); + RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REP socket"); + + rc = zmq_bind (sock, get_config(REQ_REP_END_KEY)); + RET_ON_ERR(rc == 0, "Failed to bind to %s", get_config(REQ_REP_END_KEY)); + + m_socket = sock; +out: + return ret; +} + + +int +event_service:echo_send(const string s) +{ + zmq_msg_t msg_req, msg_data; + int rc = zmq_msg_init_size(&snd_msg, s.size()+1); + RET_ON_ERR(rc == 0, "Failed to init zmq msg for %d bytes", s.size()+1); + memcpy((void *)zmq_msg_data(&snd_msg), s.str(), s.size()+1); + rc = zmq_msg_send(&snd_msg, m_socket, 0); + RET_ON_ERR (rc != -1, "Failed to send to %s", get_config(REQ_REP_END_KEY)); +out: + if (rc != 0) { + close(); + } + return rc; +} + + +int +event_service::echo_receive(string &outs, bool block) +{ + zmq_msg_t rcv_msg; + + zmq_msg_init(&rcv_msg); + + int rc = zmq_msg_recv(&rcv_msg, m_socket, ZMQ_DONTWAIT); + int err = zmq_errno(); + RET_ON_ERR (rc != -1, + "Failed to receive message from echo service err=%d", err); + + outs = string((const char *)zmq_msg_data(&rcv_msg)); +out: + zmq_msg_close(&rcv_msg); + close(); + return rc; +} + + +int +event_service::cache_start() +{ + // TODO + reurn 0; +} + + +int +event_service::cache_stop() +{ + // TODO + reurn 0; +} + + +int +event_service::cache_read(vector &lst) +{ + // TODO + reurn 0; +} + + +int +event_service::server_read(event_req_type_t &req_code, event_service_data_t &data) +{ + // TODO + reurn 0; +} + + +int +event_service::server_write(int resp_code, event_service_data_t &data) +{ + // TODO + reurn 0; +} + +int +event_service::close_service() +{ + if (m_socket = NULL) { zmq_close(m_socket); m_socket = NULL; } + return 0; +} + + diff --git a/common/events_service.h b/common/events_service.h new file mode 100644 index 000000000..36e393913 --- /dev/null +++ b/common/events_service.h @@ -0,0 +1,202 @@ +#include "string.h" +#include "events_common.h" + + +/* + * All the services uses REQ/REP pattern between caller + * centralized event service. The return code is provided + * by service in its reply. + * + * event_request goes as single part message carrying event_req_t, + * unless there is data associated. + * + * Both req & resp are either single or multi part. In case of no + * data associated, it is just request code or response return value in one part. + * In case of data, it comes in seccond part. + * + * Type of data is as decided by request. + * + * In case of echo, part2 is the string as provided in the request. + * + * The read returns as serialized vector of ZMQ messages, in part2. + */ + +typedef enum { + EVENT_CACHE_START, + EVENT_CACHE_STOP, + EVENT_CACHE_READ, + EVENT_ECHO +} event_req_type_t; + +/* + * internal service init & APIs for read & write + */ + +/* + * An internal service is provided for cache handling & miscellaneous. + * + * Clients initialize for init_client and uses the provided services + * server code init for server and use server_read & server_write + */ +class event_service { + public: + event_service(): m_socket(NULL) {} + + ~event_service() { close(); } + + init_client(void *zmq_ctx, int block_ms = -1); + + init_server(void *zmq_ctx); + + /* + * Event cache service is singleton service + * + * Any duplicate start has no impact. + * The cached events can be read only upon stop. A read before + * stop returns failure. A read w/o a start succeeds with no message. + * + */ + + + /* + * Called to start caching events + * + * This is transparently called by events_deinit_subscriber, if cache service + * was enabled. + * + * return: + * 0 - On success. + * 1 - Already running + * -1 - On failure. + */ + int cache_start(); + + /* + * Called to stop caching events + * + * This is transparently called by events_init_subscriber, if cache service + * is enabled. + * + * return: + * 0 - On success. + * 1 - Not running + * -1 - On failure. + */ + int cache_stop(); + + /* + * cache read + * + * This is transparently called by event_receive, if cache service + * is enabled. Returns the set of zmq messages as received. + * NOTE: Every event is received as 2 parts. So 2 ZMQ messages makes + * one event. + * + * An empty o/p implies no more. + * + * Internal details: + * + * Cache service caches all events until buffer overflow + * During receive using sequence+runtime Id, it keeps the count + * of missed to receive. + * + * Upon overflow, it creates a separate cache, where it keeps only + * the last event received per runtime ID. + * This is required for receiver to be able to get the missed count. + * + * The receiver API will compute the missed in the same way for + * events read from subscription channel & as well from cache. + * + * output: + * lst_msgs + * + * return: + * 0 - On success. Either stopped or none to stop. + * -1 - On failure. + */ + int cache_read(vector &lst); + + /* + * Echo send service. + * + * A service to just test out connectivity. The publisher uses + * it to shadow its connection to zmq proxy's XSUB end. This is + * called transparently by events_init_publisher. + * + * The service is closed upon failure to send as echo service is one shot only. + * + * Input: + * s - string to echo. + * + * return: + * 0 - On success + * -1 - On failure. + */ + int echo_send(const string s); + + /* + * Echo receive service. + * + * Receives the las sent echo. + * This is transparently called by event_publish on first + * publish call. This helps ensure connect XSUB end is *most* likely + * (99.9%) established, as write & read back takes one full loop. + * + * The service is closed upon read as echo service is one shot only. + * + * output: + * s - echoed string + * + * return: + * 0 - On success + * -1 - On failure + */ + int echo_receive(string &s); + + /* + * Server instance reading request from client + * + * Input: None + * + * Output: + * req_code - incoming req code + * data - Data read, if any + * + * return: + * 0 - On success + * -1 - On failure + */ + int channel_read(event_req_type_t &req_code, vector &data); + + /* + * Server instance writing respondse to client + * + * Input: + * resp_code - Return code for the request + * data - If any data to be sent along. + * + * Output: None + * + * return: + * 0 - On success + * -1 - On failure + */ + int channel_write(int resp_code, vector &data); + + + /* + * de-init/close service + */ + void close_service(); + + /* + * Check if service is active + */ + bool is_active() { return m_socket != NULL }; + +private: + void *m_socket; + +}; + + From 9763d3a22ec78290f0201756cfea441eee10ff6f Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 17 May 2022 04:29:51 +0000 Subject: [PATCH 04/97] partial update, as vm at risk --- common/events_common.h | 9 +++++ common/events_service.cpp | 78 ++++++++++++++++++++++++++++++--------- common/events_service.h | 16 ++++---- 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/common/events_common.h b/common/events_common.h index 5999af007..9e489bb68 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -57,3 +57,12 @@ void map_to_zmsg(const map_str_str_t & data, zmq_msg_t &msg); void zmsg_to_map(zmq_msg_t &msg, map_str_str_t & data); +#define u32_to_s(u32) std::to_string(u32) + +#define s_to_u32(s, u32) { stringstream _ss(s); s >> u32;} + +int int_to_msg(uint32_t u, zmq_msg_t &msg); +void msg_to_int(zmq_msg_t &msg, uint32_t &u); + +int vec_to_msg(vector &data, zmq_msg_t &msg); +void msg_to_vec(zmq_msg_t &msg, vector &data); diff --git a/common/events_service.cpp b/common/events_service.cpp index d2b89a81c..fab7905ad 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -42,17 +42,6 @@ event_service:init_server() int event_service:echo_send(const string s) { - zmq_msg_t msg_req, msg_data; - int rc = zmq_msg_init_size(&snd_msg, s.size()+1); - RET_ON_ERR(rc == 0, "Failed to init zmq msg for %d bytes", s.size()+1); - memcpy((void *)zmq_msg_data(&snd_msg), s.str(), s.size()+1); - rc = zmq_msg_send(&snd_msg, m_socket, 0); - RET_ON_ERR (rc != -1, "Failed to send to %s", get_config(REQ_REP_END_KEY)); -out: - if (rc != 0) { - close(); - } - return rc; } @@ -101,18 +90,73 @@ event_service::cache_read(vector &lst) int -event_service::server_read(event_req_type_t &req_code, event_service_data_t &data) +event_service::channel_read(int &code, vector &data) { - // TODO - reurn 0; + int more = 0, rc; + size_t more_size = sizeof (more); + + { + zmq_msg_t rcv_code; + + zmq_msg_init(&rcv_code); + rc = zmq_msg_recv(&rcv_code, m_req_socket, 0); + + RET_ON_ERR(rc != -1, "Failed to receive code"); + + msg_to_int(rcv_code, code); + zmq_msg_close(&rcv_code); + } + + rc = zmq_getsockopt (m_socket, ZMQ_RCVMORE, &more, &more_size); + RET_ON_ERR(rc == 0, "Failed to get sockopt for read channel"); + + + if (more) { + zmq_msg_t rcv_data; + + zmq_msg_init(&rcv_data); + rc = zmq_msg_recv(&rcv_data, m_req_socket, 0); + RET_ON_ERR(rc != -1, "Failed to receive data"); + + rc = zmq_getsockopt (m_socket, ZMQ_RCVMORE, &more, &more_size); + RET_ON_ERR(rc == 0, "Failed to get sockopt for read channel"); + RET_ON_ERR(!more, "Expecting more than 2 parts"); + + msg_to_vec(rcv_data, data); + zmq_msg_close(&rcv_data); + } +out: + reurn rc; } int -event_service::server_write(int resp_code, event_service_data_t &data) +event_service::channel_write(int code, vector &data) { - // TODO - reurn 0; + zmq_msg_t msg_req, msg_data; + int flag = 0; + + int rc = int_to_msg(code,msg_req); + RET_ON_ERR(rc == 0, "Failed int (%d) to msg", code); + + if (!data.empty()) { + rc = vec_to_msg(code, msg_data); + RET_ON_ERR(rc == 0, "Failed vec (%d) to msg", data.size()); + flag = ZMQ_SNDMORE; + } + + rc = zmq_msg_send (&msg_req, m_socket, flag); + RET_ON_ERR(rc == 0, "Failed to send code"); + + if (flag != 0) { + rc = zmq_msg_send (&msg_data, m_socket, 0); + RET_ON_ERR(rc == 0, "Failed to send data"); + } + +out: + zmq_msg_close(&msg_req); + zmq_msg_close(&msg_data); + return rc; } int diff --git a/common/events_service.h b/common/events_service.h index 36e393913..6b1a10d01 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -36,7 +36,7 @@ typedef enum { * An internal service is provided for cache handling & miscellaneous. * * Clients initialize for init_client and uses the provided services - * server code init for server and use server_read & server_write + * server code init for server and use read & write APIs */ class event_service { public: @@ -154,25 +154,27 @@ class event_service { int echo_receive(string &s); /* - * Server instance reading request from client + * The underlying read for req/resp from client/server * * Input: None * * Output: - * req_code - incoming req code + * code - It is event_req_type_t for request or return code + * for response * data - Data read, if any * * return: * 0 - On success * -1 - On failure */ - int channel_read(event_req_type_t &req_code, vector &data); + int channel_read(int &code, vector &data); /* - * Server instance writing respondse to client + * The under lying write for req/resp from client/server * * Input: - * resp_code - Return code for the request + * code - It is event_req_type_t for request or return code + * for response * data - If any data to be sent along. * * Output: None @@ -181,7 +183,7 @@ class event_service { * 0 - On success * -1 - On failure */ - int channel_write(int resp_code, vector &data); + int channel_write(int code, vector &data); /* From d9d24b6946eff3d6318499294c3d698b5e68e118 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Wed, 18 May 2022 16:52:39 +0000 Subject: [PATCH 05/97] intermediate saving --- common/eventd.cpp | 249 ++++++++++++++++++++++++++++++++++++++ common/eventd.h | 101 ++++++++++++++++ common/events.cpp | 3 +- common/events_common.cpp | 27 +++-- common/events_common.h | 24 ++-- common/events_pi.h | 21 +--- common/events_service.cpp | 79 +++++++----- common/events_service.h | 27 +++-- 8 files changed, 460 insertions(+), 71 deletions(-) create mode 100644 common/eventd.cpp create mode 100644 common/eventd.h diff --git a/common/eventd.cpp b/common/eventd.cpp new file mode 100644 index 000000000..18e47ed40 --- /dev/null +++ b/common/eventd.cpp @@ -0,0 +1,249 @@ +#include +#include "eventd.h" + +/* + * There are 3 threads, including the main + * + * main thread -- Runs eventd service that accepts commands event_req_type_t + * This can be used to control caching events and a no-op echo service. + * + * capture/cache service + * Saves all the events between cache start & stop + * + * Main proxy service that runs XSUB/XPUB ends + */ + +#define READ_SET_SIZE 100 + + +eventd_server::eventd_server() : m_capture(NULL) +{ + m_ctx = zmq_ctx_new(); + RET_ON_ERR(m_ctx != NULL, "Failed to get zmq ctx"); +out: + return; +} + + +eventd_server::~eventd_server() +{ + close(); +} + + +int +eventd_server::zproxy_service() +{ + int ret = -1; + SWSS_LOG_INFO("Start xpub/xsub proxy"); + + void *frontend = zmq_socket(m_ctx, ZMQ_XSUB); + RET_ON_ERR(frontend != NULL, "failing to get ZMQ_XSUB socket"); + + int rc = zmq_bind(frontend, get_config(XSUB_END_KEY)); + RET_ON_ERR(rc == 0, "Failing to bind XSUB to %s", get_config(XSUB_END_KEY)); + + void *backend = zmq_socket(m_ctx, ZMQ_XPUB); + RET_ON_ERR(backend != NULL, "failing to get ZMQ_XPUB socket"); + + rc = zmq_bind(backend, get_config(XPUB_END_KEY)); + RET_ON_ERR(rc == 0, "Failing to bind XPUB to %s", get_config(XPUB_END_KEY)); + + void *capture = zmq_socket(m_ctx, ZMQ_PUB); + RET_ON_ERR(capture != NULL, "failing to get ZMQ_XSUB socket"); + + rc = zmq_bind(capture, get_config(CAPTURE_END_KEY)); + RET_ON_ERR(rc == 0, "Failing to bind PAIR to %s", get_config(PAIR_END_KEY)); + + m_thread_proxy = thread(&eventd_server::zproxy_service_run, this, frontend, + backend, capture); + ret = 0; +out: + return ret; +} + + +void +eventd_server::zproxy_service_run(void *frontend, void *backend, void *capture) +{ + SWSS_LOG_INFO("Running xpub/xsub proxy"); + + /* runs forever until zmq context is terminated */ + zmq_proxy(frontend, backend, capture); + + zmq_close(frontend); + zmq_close(backend); + zmq_close(capture); + + SWSS_LOG_ERR("Terminating xpub/xsub proxy"); + + return 0; +} + + +int +eventd_server::capture_events() +{ + /* clean any pre-existing cache */ + int ret = -1; + + vector().swap(m_events); + map.swap(m_last_events); + + RET_ON_ERR(m_capture != NULL, "capture sock is not initialized yet"); + + while(true) { + zmq_msg_t msg; + internal_event_t event; + int more = 0; + size_t more_size = sizeof (more); + + { + zmq_msg_t pat; + zmq_msg_init(&pat); + RET_ON_ERR(zmq_msg_recv(&pat, m_capture, 0) != -1, + "Failed to capture pattern"); + zmq_msg_close(&pat); + } + + RET_ON_ERR(zmq_getsockopt (m_capture, ZMQ_RCVMORE, &more, &more_size) == 0, + "Failed to get sockopt for capture sock"); + RET_ON_ERR(more, "Event data expected, but more is false"); + + zmq_msg_init(&msg); + RET_ON_ERR(zmq_msg_recv(&msg, m_capture, 0) != -1, + "Failed to read event data"); + + string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); + zmq_msg_close(&msg); + + deserialize(s, event); + + m_last_events[event[EVENT_RUNTIME_ID]] = s; + + try + { + m_events.push_back(s); + } + catch (exception& e) + { + stringstream ss; + ss << e.what(); + SWSS_LOG_ERROR("Cache save event failed with %s events:size=%d", + ss.str().c_str(), m_events.size()); + goto out; + } + } +out: + /* Destroy the service and exit the thread */ + close(); + return 0; +} + + +int +eventd_server::eventd_service() +{ + event_service service; + + RET_ON_ERR(zproxy_service() == 0, "Failed to start zproxy_service"); + + RET_ON_ERR(service.init_server(m_ctx) == 0, "Failed to init service"); + + while(true) { + int code, resp = -1; + vector req_data, resp_data; + + RET_ON_ERR(channel_read(code, data) == 0, + "Failed to read request"); + + switch(code) { + case EVENT_CACHE_START: + if (m_capture != NULL) { + resp_code = 1; + break; + } + m_capture = zmq_socket(m_ctx, ZMQ_SUB); + RET_ON_ERR(capture != NULL, "failing to get ZMQ_XSUB socket"); + + rc = zmq_connect(capture, get_config(CAPTURE_END_KEY)); + RET_ON_ERR(rc == 0, "Failing to bind PAIR to %s", get_config(PAIR_END_KEY)); + + rc = zmq_setsockopt(sub_read, ZMQ_SUBSCRIBE, "", 0); + RET_ON_ERR(rc == 0, "Failing to ZMQ_SUBSCRIBE"); + + /* Kick off the service */ + m_thread_capture = thread(&eventd_server::capture_events, this); + + resp_code = 0; + break; + + + case EVENT_CACHE_STOP: + resp_code = 0; + if (m_capture != NULL) { + close(m_capture); + m_capture = NULL; + + /* Wait for thread to end */ + m_thread_capture.join(); + } + break; + + + case EVENT_CACHE_READ: + resp_code = 0; + + if (m_events.empty()) { + for (last_events_t::iterator it = m_last_events.begin(); + it != m_last_events.end(); ++it) { + m_events.push_back(it->second); + } + last_events_t().swap(m_last_events); + } + + int sz = m_events.size() < READ_SET_SIZE ? m_events.size() : READ_SET_SIZE; + + auto it = std::next(m_events.begin(), sz); + move(m_events.begin(), m_events.end(), back_inserter(resp_data)); + + if (sz == m_events.size()) { + events_data_lst_t().swap(m_events); + } else { + m_events.erase(m_events.begin(), it); + } + break; + + + case EVENT_ECHO: + resp_code = 0; + resp_data.swap(req_data); + + default: + SWSS_LOG_ERROR("Unexpected request: %d", code); + assert(false); + break; + } + RET_ON_ERR(channel_write(resp_code, resp_data) == 0, + "Failed to write response back"); + } +out: + /* Breaks here on fatal failure */ + if (m_capture != NULL) { + close(m_capture); + m_capture = NULL; + } + close(); + m_thread_proxy.join(); + m_thread_capture.join(); + return 0; +} + + + +void eventd_server::close() +{ + zmq_ctx_term(m_ctx); m_ctx = NULL; + +} + diff --git a/common/eventd.h b/common/eventd.h new file mode 100644 index 000000000..06401175f --- /dev/null +++ b/common/eventd.h @@ -0,0 +1,101 @@ +#include "events_service.h" + +typedef map last_events_t; + +class eventd_server { + public: + /* Creates the zmq context */ + eventd_server(); + + ~eventd_server(); + + /* + * Main eventd service loop that honors event_req_type_t + * + * For echo, it just echoes + * + * FOr cache start, create the SUB end of capture and kick off + * capture_events thread. Upon cache stop command, close the handle + * which will stop the caching thread with read failure. + * + * for cache read, returns the collected events as subset of + * strings. + * + */ + int eventd_service(); + + + /* + * For any fatal failure, terminate the entire run across threads + * by deleting the zmq context. + */ + void close(); + + private: + /* + * Started by eventd_service. + * Creates XPUB & XSUB end points. + * Bind the same + * Create a PUB socket end point for capture and bind. + * Call run_proxy method with sockets in a dedicated thread. + * Thread runs forever until the zmq context is terminated. + */ + int zproxy_service(); + int zproxy_service_run(void *front, void *back, void *capture); + + + /* + * Capture/Cache service + * + * The service started in a dedicted thread upon demand. + * It expects SUB end of capture created & connected to the PUB + * capture end in zproxy service. + * + * It goes in a forever loop, until the zmq read fails, which will happen + * if the capture/SUB end is closed. The stop cache service will close it, + * while start cache service creates & connects. + * + * Hence this thread/function is active between cache start & stop. + * + * Each event is 2 parts. It drops the first part, which is + * more for filtering events. It creates string from second part + * and saves it. + * + * The string is the serialized version of internal_event_ref + * + * It keeps two sets of data + * 1) List of all events received in vector in same order as received + * 2) Map of last event from each runtime id + * + * We add to the vector as much as allowed by vector and as well + * the available memory. When mem exhausts, just keep updating map + * with last event from that sender. + * + * The sequence number in map will help assess the missed count. + * + * Thread is started upon creating SUB end of capture socket. + */ + int capture_events(); + + + private: + void *m_ctx; + + events_data_lst_t m_events; + + last_events_t m_last_events; + + void *m_capture; + + + thread m_thread_proxy; + thread m_thread_capture; +}; + + + + + + + + diff --git a/common/events.cpp b/common/events.cpp index d2c9349fe..c2e5037ac 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -91,7 +91,8 @@ EventPublisher::event_publish(const string tag, const event_params_t *params) } event_data[EVENT_RUNTIME_ID] = m_runtime_id; - map_to_zmsg(event_data, msg); + RET_ON_ERR(map_to_zmsg(event_data, msg) == 0, + "Failed to buildmsg data size=%d", event_data.size()); // Send the message // First part -- The event-source/pattern diff --git a/common/events_common.cpp b/common/events_common.cpp index f7ff07e25..3ad740aea 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -1,4 +1,5 @@ #include "events_common.h" +#include #include #include #include @@ -11,7 +12,7 @@ map_str_str_t cfg_data = { CFG_VAL(XSUB_END_KEY, "tcp://127.0.0.1:5570"), CFG_VAL(XPUB_END_KEY, "tcp://127.0.0.1:5571"), CFG_VAL(REQ_REP_END_KEY, "tcp://127.0.0.1:5572"), - CFG_VAL(PAIR_END_KEY, "tcp://127.0.0.1:5573"), + CFG_VAL(CAPTURE_END_KEY, "tcp://127.0.0.1:5573"), CFG_VAL(STATS_UPD_SECS, "5") }; @@ -80,14 +81,15 @@ get_timestamp() /* - * Way to serialize map + * Way to serialize map or vector * boost::archive::text_oarchive could be used to archive any struct/class * but that class needs some additional support, that declares * boost::serialization::access as private friend and couple more tweaks * std::map inherently supports serialization */ +template const string -serialize(const map_str_str_t& data) +serialize(const Map& data) { std::stringstream ss; boost::archive::text_oarchive oarch(ss); @@ -95,8 +97,9 @@ serialize(const map_str_str_t& data) return ss.str(); } +template void -deserialize(const string& s, map_str_str_t& data) +deserialize(const string& s, Map& data) { std::stringstream ss; ss << s; @@ -106,20 +109,28 @@ deserialize(const string& s, map_str_str_t& data) } +template void -map_to_zmsg(const map_str_str_t& data, zmq_msg_t &msg) +map_to_zmsg(const Map& data, zmq_msg_t &msg) { string s = serialize(data); - zmq_msg_init_size(&msg, s.size()); - strncpy((char *)zmq_msg_data(&msg), s.c_str(), s.size()); + int rc = zmq_msg_init_size(&msg, s.size()); + if (rc == 0) { + strncpy((char *)zmq_msg_data(&msg), s.c_str(), s.size()); + } + return rc; } +template void -zmsg_to_map(zmq_msg_t &msg, map_str_str_t& data) +zmsg_to_map(zmq_msg_t &msg, Map& data) { string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); deserialize(s, data); } + + + diff --git a/common/events_common.h b/common/events_common.h index 9e489bb68..9789cdeaa 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -1,9 +1,11 @@ /* * common APIs used by events code. */ +#include #include #include #include +#include #include "string.h" #include "json.hpp" #include "zmq.h" @@ -15,10 +17,15 @@ using namespace std; using namespace chrono; -#define RET_ON_ERR(res, ...) {\ - if (!(res)) \ - SWSS_LOG_ERROR(__VA_ARGS__); } - goto out; +extern int errno; + +#define RET_ON_ERR(res, msg, ...)\ + if (!(res)) {\ + int e = errno; \ + int z = zmq_errno(); \ + string fmt = "errno:%d zmq_errno:%d " + msg; \ + SWSS_LOG_ERROR(fmt.c_str(), e, z, ##__VA_ARGS__); \ + goto out; } #define ERR_CHECK(res, ...) {\ if (!(res)) \ @@ -38,7 +45,7 @@ typedef map map_str_str_t; #define XSUB_END_KEY "xsub_path" #define XPUB_END_KEY "xpub_path" #define REQ_REP_END_KEY "req_rep_path" -#define PAIR_END_KEY "pair_path" +#define CAPTURE_END_KEY "capture_path" #define STATS_UPD_SECS "stats_upd_secs" /* init config from file */ @@ -53,7 +60,7 @@ const string serialize(const map_str_str_t & data); void deserialize(const string& s, map_str_str_t & data); -void map_to_zmsg(const map_str_str_t & data, zmq_msg_t &msg); +int map_to_zmsg(const map_str_str_t & data, zmq_msg_t &msg); void zmsg_to_map(zmq_msg_t &msg, map_str_str_t & data); @@ -61,8 +68,3 @@ void zmsg_to_map(zmq_msg_t &msg, map_str_str_t & data); #define s_to_u32(s, u32) { stringstream _ss(s); s >> u32;} -int int_to_msg(uint32_t u, zmq_msg_t &msg); -void msg_to_int(zmq_msg_t &msg, uint32_t &u); - -int vec_to_msg(vector &data, zmq_msg_t &msg); -void msg_to_vec(zmq_msg_t &msg, vector &data); diff --git a/common/events_pi.h b/common/events_pi.h index 8a7025d4d..13528c135 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -31,26 +31,15 @@ using namespace std; #define EVENT_RUNTIME_ID "runtime_id" #define EVENT_SEQUENCE "sequence" -map _internal_event_t = -{ - { EVENT_STR_DATA, "" }, - { EVENT_RUNTIME_ID, "" }, - { EVENT_SEQUENCE +typedef map internal_event_t; + +tyepdef string runtime_id_t; + internal_event_t internal_event_ref = { { EVENT_STR_DATA, "" }, { EVENT_RUNTIME_ID, "" }, { EVENT_SEQUENCE, "" } }; -typedef struct _internal_event_t { - - _internal_event_t(event_str_t e, uuid_t r, uint32_t s): - event(e), runtime_id(r), sequence(s) {}; - - event_str_t event; - uuid_t runtime_id; - uint32_t sequence; -} internal_event_t; - /* Base class for publisher & subscriber */ class events_base { @@ -83,7 +72,7 @@ class EventPublisher : public events_base { zmq_msg_t m_zmsg_source; string m_event_source; - uuid_t m_runtime_id; + runtime_id_t m_runtime_id; uint32_t m_sequence; bool m_init; diff --git a/common/events_service.cpp b/common/events_service.cpp index fab7905ad..9124205d2 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -42,25 +42,27 @@ event_service:init_server() int event_service:echo_send(const string s) { + vector l = { s }; + + return channel_write(EVENT_ECHO, l); + } int -event_service::echo_receive(string &outs, bool block) +event_service::echo_receive(string &outs) { - zmq_msg_t rcv_msg; - - zmq_msg_init(&rcv_msg); + vector l; + int code; - int rc = zmq_msg_recv(&rcv_msg, m_socket, ZMQ_DONTWAIT); - int err = zmq_errno(); - RET_ON_ERR (rc != -1, - "Failed to receive message from echo service err=%d", err); + int rc = channel_read(code, l); + RET_ON_ERR(rc == 0, "failing to read echo"); - outs = string((const char *)zmq_msg_data(&rcv_msg)); + RET_ON_ERR (code == 0, "echo receive resp %d not 0", code); + RET_ON_ERR (l.size() == 1, "echo received resp size %d is not 1", l.size()); + + outs = l[0]; out: - zmq_msg_close(&rcv_msg); - close(); return rc; } @@ -68,24 +70,26 @@ event_service::echo_receive(string &outs, bool block) int event_service::cache_start() { - // TODO - reurn 0; + int rc = send_recv(EVENT_CACHE_START); + if (rc == 0) { + /* To shadow subscribe connect required for cache start */ + send_recv(EVENT_ECHO); + } + return rc; } int event_service::cache_stop() { - // TODO - reurn 0; + return send_recv(EVENT_CACHE_STOP); } int -event_service::cache_read(vector &lst) +event_service::cache_read(vector &lst) { - // TODO - reurn 0; + return send_recv(EVENT_CACHE_READ, lst); } @@ -98,12 +102,10 @@ event_service::channel_read(int &code, vector &data) { zmq_msg_t rcv_code; - zmq_msg_init(&rcv_code); rc = zmq_msg_recv(&rcv_code, m_req_socket, 0); - RET_ON_ERR(rc != -1, "Failed to receive code"); - msg_to_int(rcv_code, code); + zmsg_to_map(rcv_code, code); zmq_msg_close(&rcv_code); } @@ -114,7 +116,6 @@ event_service::channel_read(int &code, vector &data) if (more) { zmq_msg_t rcv_data; - zmq_msg_init(&rcv_data); rc = zmq_msg_recv(&rcv_data, m_req_socket, 0); RET_ON_ERR(rc != -1, "Failed to receive data"); @@ -122,7 +123,7 @@ event_service::channel_read(int &code, vector &data) RET_ON_ERR(rc == 0, "Failed to get sockopt for read channel"); RET_ON_ERR(!more, "Expecting more than 2 parts"); - msg_to_vec(rcv_data, data); + zmsg_to_map(rcv_data, data); zmq_msg_close(&rcv_data); } out: @@ -131,16 +132,16 @@ event_service::channel_read(int &code, vector &data) int -event_service::channel_write(int code, vector &data) +event_service::channel_write(int code, const vector &data) { zmq_msg_t msg_req, msg_data; int flag = 0; - int rc = int_to_msg(code,msg_req); + int rc = map_to_zmsg(code,msg_req); RET_ON_ERR(rc == 0, "Failed int (%d) to msg", code); if (!data.empty()) { - rc = vec_to_msg(code, msg_data); + rc = map_to_zmsg(code, msg_data); RET_ON_ERR(rc == 0, "Failed vec (%d) to msg", data.size()); flag = ZMQ_SNDMORE; } @@ -159,6 +160,31 @@ event_service::channel_write(int code, vector &data) return rc; } + +int +event_service::send_recv(int code, vector *p = NULL) +{ + vector l; + int resp; + + if(p == NULL) { + p = &l; + } + + int rc = channel_write(code, *p); + RET_ON_ERR(rc == 0, "failing to send code=%d", code); + + rc = channel_read(resp, *p); + RET_ON_ERR(rc == 0, "failing to read resp for code=%d", code); + + rc = resp; + RET_ON_ERR (rc == 0, "echo receive resp %d not 0 for code=%d", resp, code); + +out: + return rc; +} + + int event_service::close_service() { @@ -166,4 +192,3 @@ event_service::close_service() return 0; } - diff --git a/common/events_service.h b/common/events_service.h index 6b1a10d01..f943dd05d 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -28,6 +28,9 @@ typedef enum { EVENT_ECHO } event_req_type_t; +typedef string events_data_type_t; +typedef vector events_data_lst_t; + /* * internal service init & APIs for read & write */ @@ -44,9 +47,9 @@ class event_service { ~event_service() { close(); } - init_client(void *zmq_ctx, int block_ms = -1); + int init_client(void *zmq_ctx, int block_ms = -1); - init_server(void *zmq_ctx); + int init_server(void *zmq_ctx); /* * Event cache service is singleton service @@ -88,9 +91,10 @@ class event_service { * cache read * * This is transparently called by event_receive, if cache service - * is enabled. Returns the set of zmq messages as received. - * NOTE: Every event is received as 2 parts. So 2 ZMQ messages makes - * one event. + * is enabled. + * Each event is received as 2 parts. First part is more a filter for + * hence dropped. The second part is returned as string. + * The string is the serialized form of internal_event_t. * * An empty o/p implies no more. * @@ -114,7 +118,7 @@ class event_service { * 0 - On success. Either stopped or none to stop. * -1 - On failure. */ - int cache_read(vector &lst); + int cache_read(events_data_lst_t &lst); /* * Echo send service. @@ -167,7 +171,7 @@ class event_service { * 0 - On success * -1 - On failure */ - int channel_read(int &code, vector &data); + int channel_read(int &code, events_data_lst_t &data); /* * The under lying write for req/resp from client/server @@ -183,7 +187,14 @@ class event_service { * 0 - On success * -1 - On failure */ - int channel_write(int code, vector &data); + int channel_write(int code, const events_data_lst_t &data); + + /* + * send and receive helper + */ + int send_recv(int code, events_data_lst_t *p = NULL); + + /* From d68c20450e04e47a02632cad4a518da2533d3be9 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 19 May 2022 23:51:05 +0000 Subject: [PATCH 06/97] First run code complete --- common/eventd.cpp | 249 ----------------------------------- common/eventd.h | 101 -------------- common/events.cpp | 268 ++++++++++++++++++++++++++++++++------ common/events.h | 7 +- common/events_common.cpp | 4 +- common/events_common.h | 141 +++++++++++++++++++- common/events_pi.h | 134 ++++++++----------- common/events_service.cpp | 94 ++++--------- common/events_service.h | 54 ++++++-- 9 files changed, 492 insertions(+), 560 deletions(-) delete mode 100644 common/eventd.cpp delete mode 100644 common/eventd.h diff --git a/common/eventd.cpp b/common/eventd.cpp deleted file mode 100644 index 18e47ed40..000000000 --- a/common/eventd.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include -#include "eventd.h" - -/* - * There are 3 threads, including the main - * - * main thread -- Runs eventd service that accepts commands event_req_type_t - * This can be used to control caching events and a no-op echo service. - * - * capture/cache service - * Saves all the events between cache start & stop - * - * Main proxy service that runs XSUB/XPUB ends - */ - -#define READ_SET_SIZE 100 - - -eventd_server::eventd_server() : m_capture(NULL) -{ - m_ctx = zmq_ctx_new(); - RET_ON_ERR(m_ctx != NULL, "Failed to get zmq ctx"); -out: - return; -} - - -eventd_server::~eventd_server() -{ - close(); -} - - -int -eventd_server::zproxy_service() -{ - int ret = -1; - SWSS_LOG_INFO("Start xpub/xsub proxy"); - - void *frontend = zmq_socket(m_ctx, ZMQ_XSUB); - RET_ON_ERR(frontend != NULL, "failing to get ZMQ_XSUB socket"); - - int rc = zmq_bind(frontend, get_config(XSUB_END_KEY)); - RET_ON_ERR(rc == 0, "Failing to bind XSUB to %s", get_config(XSUB_END_KEY)); - - void *backend = zmq_socket(m_ctx, ZMQ_XPUB); - RET_ON_ERR(backend != NULL, "failing to get ZMQ_XPUB socket"); - - rc = zmq_bind(backend, get_config(XPUB_END_KEY)); - RET_ON_ERR(rc == 0, "Failing to bind XPUB to %s", get_config(XPUB_END_KEY)); - - void *capture = zmq_socket(m_ctx, ZMQ_PUB); - RET_ON_ERR(capture != NULL, "failing to get ZMQ_XSUB socket"); - - rc = zmq_bind(capture, get_config(CAPTURE_END_KEY)); - RET_ON_ERR(rc == 0, "Failing to bind PAIR to %s", get_config(PAIR_END_KEY)); - - m_thread_proxy = thread(&eventd_server::zproxy_service_run, this, frontend, - backend, capture); - ret = 0; -out: - return ret; -} - - -void -eventd_server::zproxy_service_run(void *frontend, void *backend, void *capture) -{ - SWSS_LOG_INFO("Running xpub/xsub proxy"); - - /* runs forever until zmq context is terminated */ - zmq_proxy(frontend, backend, capture); - - zmq_close(frontend); - zmq_close(backend); - zmq_close(capture); - - SWSS_LOG_ERR("Terminating xpub/xsub proxy"); - - return 0; -} - - -int -eventd_server::capture_events() -{ - /* clean any pre-existing cache */ - int ret = -1; - - vector().swap(m_events); - map.swap(m_last_events); - - RET_ON_ERR(m_capture != NULL, "capture sock is not initialized yet"); - - while(true) { - zmq_msg_t msg; - internal_event_t event; - int more = 0; - size_t more_size = sizeof (more); - - { - zmq_msg_t pat; - zmq_msg_init(&pat); - RET_ON_ERR(zmq_msg_recv(&pat, m_capture, 0) != -1, - "Failed to capture pattern"); - zmq_msg_close(&pat); - } - - RET_ON_ERR(zmq_getsockopt (m_capture, ZMQ_RCVMORE, &more, &more_size) == 0, - "Failed to get sockopt for capture sock"); - RET_ON_ERR(more, "Event data expected, but more is false"); - - zmq_msg_init(&msg); - RET_ON_ERR(zmq_msg_recv(&msg, m_capture, 0) != -1, - "Failed to read event data"); - - string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); - zmq_msg_close(&msg); - - deserialize(s, event); - - m_last_events[event[EVENT_RUNTIME_ID]] = s; - - try - { - m_events.push_back(s); - } - catch (exception& e) - { - stringstream ss; - ss << e.what(); - SWSS_LOG_ERROR("Cache save event failed with %s events:size=%d", - ss.str().c_str(), m_events.size()); - goto out; - } - } -out: - /* Destroy the service and exit the thread */ - close(); - return 0; -} - - -int -eventd_server::eventd_service() -{ - event_service service; - - RET_ON_ERR(zproxy_service() == 0, "Failed to start zproxy_service"); - - RET_ON_ERR(service.init_server(m_ctx) == 0, "Failed to init service"); - - while(true) { - int code, resp = -1; - vector req_data, resp_data; - - RET_ON_ERR(channel_read(code, data) == 0, - "Failed to read request"); - - switch(code) { - case EVENT_CACHE_START: - if (m_capture != NULL) { - resp_code = 1; - break; - } - m_capture = zmq_socket(m_ctx, ZMQ_SUB); - RET_ON_ERR(capture != NULL, "failing to get ZMQ_XSUB socket"); - - rc = zmq_connect(capture, get_config(CAPTURE_END_KEY)); - RET_ON_ERR(rc == 0, "Failing to bind PAIR to %s", get_config(PAIR_END_KEY)); - - rc = zmq_setsockopt(sub_read, ZMQ_SUBSCRIBE, "", 0); - RET_ON_ERR(rc == 0, "Failing to ZMQ_SUBSCRIBE"); - - /* Kick off the service */ - m_thread_capture = thread(&eventd_server::capture_events, this); - - resp_code = 0; - break; - - - case EVENT_CACHE_STOP: - resp_code = 0; - if (m_capture != NULL) { - close(m_capture); - m_capture = NULL; - - /* Wait for thread to end */ - m_thread_capture.join(); - } - break; - - - case EVENT_CACHE_READ: - resp_code = 0; - - if (m_events.empty()) { - for (last_events_t::iterator it = m_last_events.begin(); - it != m_last_events.end(); ++it) { - m_events.push_back(it->second); - } - last_events_t().swap(m_last_events); - } - - int sz = m_events.size() < READ_SET_SIZE ? m_events.size() : READ_SET_SIZE; - - auto it = std::next(m_events.begin(), sz); - move(m_events.begin(), m_events.end(), back_inserter(resp_data)); - - if (sz == m_events.size()) { - events_data_lst_t().swap(m_events); - } else { - m_events.erase(m_events.begin(), it); - } - break; - - - case EVENT_ECHO: - resp_code = 0; - resp_data.swap(req_data); - - default: - SWSS_LOG_ERROR("Unexpected request: %d", code); - assert(false); - break; - } - RET_ON_ERR(channel_write(resp_code, resp_data) == 0, - "Failed to write response back"); - } -out: - /* Breaks here on fatal failure */ - if (m_capture != NULL) { - close(m_capture); - m_capture = NULL; - } - close(); - m_thread_proxy.join(); - m_thread_capture.join(); - return 0; -} - - - -void eventd_server::close() -{ - zmq_ctx_term(m_ctx); m_ctx = NULL; - -} - diff --git a/common/eventd.h b/common/eventd.h deleted file mode 100644 index 06401175f..000000000 --- a/common/eventd.h +++ /dev/null @@ -1,101 +0,0 @@ -#include "events_service.h" - -typedef map last_events_t; - -class eventd_server { - public: - /* Creates the zmq context */ - eventd_server(); - - ~eventd_server(); - - /* - * Main eventd service loop that honors event_req_type_t - * - * For echo, it just echoes - * - * FOr cache start, create the SUB end of capture and kick off - * capture_events thread. Upon cache stop command, close the handle - * which will stop the caching thread with read failure. - * - * for cache read, returns the collected events as subset of - * strings. - * - */ - int eventd_service(); - - - /* - * For any fatal failure, terminate the entire run across threads - * by deleting the zmq context. - */ - void close(); - - private: - /* - * Started by eventd_service. - * Creates XPUB & XSUB end points. - * Bind the same - * Create a PUB socket end point for capture and bind. - * Call run_proxy method with sockets in a dedicated thread. - * Thread runs forever until the zmq context is terminated. - */ - int zproxy_service(); - int zproxy_service_run(void *front, void *back, void *capture); - - - /* - * Capture/Cache service - * - * The service started in a dedicted thread upon demand. - * It expects SUB end of capture created & connected to the PUB - * capture end in zproxy service. - * - * It goes in a forever loop, until the zmq read fails, which will happen - * if the capture/SUB end is closed. The stop cache service will close it, - * while start cache service creates & connects. - * - * Hence this thread/function is active between cache start & stop. - * - * Each event is 2 parts. It drops the first part, which is - * more for filtering events. It creates string from second part - * and saves it. - * - * The string is the serialized version of internal_event_ref - * - * It keeps two sets of data - * 1) List of all events received in vector in same order as received - * 2) Map of last event from each runtime id - * - * We add to the vector as much as allowed by vector and as well - * the available memory. When mem exhausts, just keep updating map - * with last event from that sender. - * - * The sequence number in map will help assess the missed count. - * - * Thread is started upon creating SUB end of capture socket. - */ - int capture_events(); - - - private: - void *m_ctx; - - events_data_lst_t m_events; - - last_events_t m_last_events; - - void *m_capture; - - - thread m_thread_proxy; - thread m_thread_capture; -}; - - - - - - - - diff --git a/common/events.cpp b/common/events.cpp index c2e5037ac..eec01b18c 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -1,12 +1,16 @@ #include "events_pi.h" -lst_publishers_t EventPublisher::s_publishers = lst_publishers_t(); +/* + * Track created publishers to avoid duplicates + * As we track missed event count by publishing instances, avoiding + * duplicates helps reduce load. + */ +typedef map lst_publishers_t; +lst_publishers_t s_publishers; EventPublisher::EventPublisher(const string source) : m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0), m_init(false) { - uuuid_clear(m_runtime_id); - } int EventPublisher::init(const string event_source, int block_ms) @@ -28,9 +32,6 @@ int EventPublisher::init(const string event_source, int block_ms) rc = m_event_svc.echo_send("hello"); RET_ON_ERR (rc == 0, "Failed to echo send in event service"); - zmq_msg_init_size(&m_zmsg_source, event_source.size()); - memcpy((char *)zmq_msg_data(&m_zmsg_source), event_source, event_source.size()); - m_event_source(event_source); uuid_t id; @@ -44,9 +45,7 @@ int EventPublisher::init(const string event_source, int block_ms) EventPublisher::~EventPublisher() { - zmq_msg_close(&m_zmsg_source); zmq_close(m_socket); - zmq_close(m_echo_socket); zmq_ctx_term(m_zmq_ctx); } @@ -54,8 +53,6 @@ EventPublisher::~EventPublisher() void EventPublisher::event_publish(const string tag, const event_params_t *params) { - zmq_msg_t msg; - if (m_event_service.is_active()) { string s; @@ -82,30 +79,10 @@ EventPublisher::event_publish(const string tag, const event_params_t *params) ++m_sequence; internal_event_t event_data; event_data[EVENT_STR_DATA] = serialize(event_str); - { - stringstream ss; - - ss << m_sequence; - - event_data[EVENT_SEQUENCE] = ss.str(); - } event_data[EVENT_RUNTIME_ID] = m_runtime_id; + event_data[EVENT_SEQUENCE] = seq_to_str(m_sequence); - RET_ON_ERR(map_to_zmsg(event_data, msg) == 0, - "Failed to buildmsg data size=%d", event_data.size()); - - // Send the message - // First part -- The event-source/pattern - // Second part -- Metadata - // Third part -- Params, if given - // - RET_ON_ERR(zmq_msg_send (&m_zmsg_source, m_socket, ZMQ_SNDMORE) != -1, - "Failed to publish part 1 to %s", XSUB_PATH); - RET_ON_ERR(zmq_msg_send (&msg, m_socket, 0) != -1, - "Failed to publish part 2 to %s", XSUB_PATH); -out: - zmq_msg_close(&msg_metadata); - + return zmq_message_send(m_event_source, event_data); } event_handle_t @@ -127,7 +104,7 @@ events_init_publisher(const string event_source, int block_millisecs) } else { ret = p; - s_publishers[key] = ret; + s_publishers[key] = p; } } return ret; @@ -137,19 +114,15 @@ void events_deinit_publisher(event_handle_t &handle) { lst_publishers_t::iterator it; - EventPublisher *pub = dynamic_cast(&handle); + EventPublisher *pub = NULL; for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { if (it->second == handle) { + delete it->second; + s_publishers.erase(it); break; } } - - if (it != s_publishers.end() { - s_publishers.erase(it); - - delete pub; - } handle = NULL; } @@ -157,18 +130,227 @@ events_deinit_publisher(event_handle_t &handle) void event_publish(event_handle_t handle, const string tag, const event_params_t *params) { - EventPublisher *pub = dynamic_cast(handle); - for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { if (it->second == handle) { - pub->event_publish(tag, params); + it->second->event_publish(tag, params); break; } } } +EventSubscriber::EventSubscriber() : m_zmq_ctx(NULL), m_socket(NULL), m_init(false), + m_cache_read(false) +{}; + + +EventSubscriber::~EventSubscriber() +{ + /* + * Call init cache + * Send & recv echo to ensure cache service made the connect, which is async. + * + * Read events for 2 seconds in non-block mode to drain the local zmq cache + * maintained by zmq lib. + * + * Disconnect the SUBS socket + * Send the read events to cache service star, as initial stock. + */ + int rc = 0; + + if (m_use_cache) { + events_data_lst_t events; + + rc = m_event_svc.cache_init(); + RET_ON_ERR(rc == 0, "Failed to init the cache"); + + /* Shadow the cache init request, as it is async */ + m_event_svc.send_recv(EVENT_ECHO); + + /* read for 2 seconds in non-block mode, to drain any local cache */ + chrono::steady_clock::timepoint start = chrono::steady_clock::now(); + while(true) { + string source, evt_str; + rc = zmq_message_read(m_socket, ZMQ_DONTWAIT, source, evt_str); + if (rc == -1) { + if (zerrno == EAGAIN) { + rc = 0; + } + break; + } + events.push_back(evt_str); + if(chrono::steady_clock::now() - start > chrono::seconds(2)) + break; + } + + /* Start cache service with locally read events as initial stock */ + RET_ON_ERR(m_event_svc.cache_start(events) == 0, + "Failed to send cache start"); + } +out: + zmq_close(m_socket); + zmq_ctx_term(m_zmq_ctx); +} +int +EventSubscriber::init(bool use_cache, const event_subscribe_sources_t *subs_sources) +{ + /* + * Initiate SUBS connection to XPUB end point. + * Send subscribe request + * + * If cache use enabled, buy some time to shadow + * the earlier SUBS connect, which is async, before + * calling event_service to stop cache + */ + m_zmq_ctx = zmq_ctx_new(); + + m_socket = zmq_socket (m_zmq_ctx, ZMQ_SUB); + + int rc = zmq_connect (m_socket, get_config(XPUB_END_KEY)); + RET_ON_ERR(rc == 0, "Subscriber fails to connect %s", get_config(XPUB_END_KEY)); + + if ((subs_sources == NULL) || (subs_sources->empty())) { + rc = zmq_setsockopt(sub_read, ZMQ_SUBSCRIBE, "", 0); + RET_ON_ERR(rc == 0, "Fails to set option"); + } + else { + for (const auto e: *subs_sources) { + rc = zmq_setsockopt(sub_read, ZMQ_SUBSCRIBE, e.c_str(), e.size()); + RET_ON_ERR(rc == 0, "Fails to set option"); + } + } + + if (use_cache) { + rc = m_event_svc.init_client(m_zmq_ctx); + RET_ON_ERR(rc == 0, "Fails to init the service"); + + /* Shadow the cache SUBS connect request, as it is async */ + m_event_svc.send_recv(EVENT_ECHO); + + if (m_event_svc.cache_stop() == 0) { + // Stopped an active cache + m_cache_read = true; + } + m_use_cache = true; + } + m_init = true; +out: + return rc; +} + + +void +EventSubscriber::prune_track() +{ + map > lst; + + for(const auto e: m_track) { + lst[e.second.epoch_secs].push_back(e.first); + } + + map >::const_iterator itc = lst.begin(); + for(; (itc != lst.end()) && (m_track.size() > MAX_PUBLISHERS_COUNT); ++itc) { + for (const auto r: itc->second) { + m_track.erase(r); + } + } + +} + + +int +EventSubscriber::event_receive(event_str_t &event, int &missed_cnt) +{ + event.clear(); + while (event.empty()) { + internal_event_t event_data; + int rc = 0; + + if (m_cache_read && m_from_cache.empty()) { + m_event_svc.cache_read(m_from_cache); + m_cache_read = !m_from_cache.empty(); + } + + if (!m_from_cache.empty()) { + + events_data_lst_t::iterator it = m_from_cache.begin(); + deserialize(*it, event_data); + m_from_cache.erase(it); + + } + else { + /* Read from SUBS channel */ + string evt_source; + rc = zmq_message_read(m_socket, 0, evt_source, event_data); + RET_ON_ERR(rc == 0, "Failed to read message from sock"); + } + + /* Find any missed events for this runtime ID */ + missed_cnt = 0; + track_info_t::iterator it = m_track.find(event_data[EVENT_RUNTIME_ID]); + if (it != m_track.end()) { + sequence_t seq = events_base::str_to_seq(event_data[EVENT_SEQUENCE]); + /* current seq - last read - 1 == 0 if none missed */ + missed_cnt = seq - it->second.seq - 1; + it->second = evt_info_t(seq); + } + else { + if (m_track.size() > (MAX_PUBLISHERS_COUNT + 10)) { + prune_track(); + m_track[event_data[EVENT_RUNTIME_ID] = evt_info_t(seq); + } + } + if (missed_cnt >= 0) { + event = event_data[EVENT_STR_DATA]; + } + } +out: + return rc; + +} + + +/* Expect only one subscriber per process */ +EventSubscriber *s_subscriber = NULL; + +event_handle_t +events_init_subscriber(bool use_cache=false, + const event_subscribe_sources_t *sources=NULL) +{ + if (s_subscriber == NULL) { + EventSubscriber *p = new EventSubscriber(); + + RET_ON_ERR(p->init(use_cache, sources) == 0, + "Failed to init subscriber"); + + s_subscriber = p; + } +out: + return s_subscriber; +} + + +void +events_deinit_subscriber(event_handle_t &handle) +{ + if ((handle == s_subscriber) && (s_subscriber != NULL)) { + delete s_subscriber; + s_subscriber = NULL; + } + handle = NULL; +} + + + +int +event_receive(event_handle_t handle, event_str_t &event, int &missed_cnt) +{ + if ((handle == s_subscriber) && (s_subscriber != NULL)) { + return s_subscriber->event_receive(event, missed_cnt); + } + return -1; +} diff --git a/common/events.h b/common/events.h index c4b0e2589..64639b09b 100644 --- a/common/events.h +++ b/common/events.h @@ -2,13 +2,14 @@ * Events library * * APIs are for publishing & receiving events with source, tag and params along with timestamp. + * Used by event publishers and those interested in receiving published events. + * Publishers are multiple sources, as processes running in hosts & containers. + * Receiver are often few. Telmetry container runs a receiver. * */ -class events_base; - -typedef events_base* event_handle_t; +typedef void* event_handle_t; /* * Initialize an event publisher instance for an event source. diff --git a/common/events_common.cpp b/common/events_common.cpp index 3ad740aea..dda01620b 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -4,6 +4,8 @@ #include #include +int zerrno = 0; + /* * defaults for all config entries */ @@ -110,7 +112,7 @@ deserialize(const string& s, Map& data) template -void +int map_to_zmsg(const Map& data, zmq_msg_t &msg) { string s = serialize(data); diff --git a/common/events_common.h b/common/events_common.h index 9789cdeaa..af76e0089 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -18,13 +18,15 @@ using namespace std; using namespace chrono; extern int errno; +extern int zerrno; + #define RET_ON_ERR(res, msg, ...)\ if (!(res)) {\ int e = errno; \ - int z = zmq_errno(); \ + zerrno = zmq_errno(); \ string fmt = "errno:%d zmq_errno:%d " + msg; \ - SWSS_LOG_ERROR(fmt.c_str(), e, z, ##__VA_ARGS__); \ + SWSS_LOG_ERROR(fmt.c_str(), e, zerrno, ##__VA_ARGS__); \ goto out; } #define ERR_CHECK(res, ...) {\ @@ -47,11 +49,31 @@ typedef map map_str_str_t; #define REQ_REP_END_KEY "req_rep_path" #define CAPTURE_END_KEY "capture_path" #define STATS_UPD_SECS "stats_upd_secs" +#define CACHE_MAX_CNT "cache_max_cnt" /* init config from file */ void read_init_config(const char *fname); /* Provide a key for configurable entity */ +template +T get_config_data(const string key, T def) +{ + string s(get_config(key)); + + if (s.empty()) { + return def; + } + else { + stringstream ss(get_config(key)); + + T v; + ss >> v; + + return v; + } +} + + string get_config(const string key); const string get_timestamp(); @@ -60,11 +82,118 @@ const string serialize(const map_str_str_t & data); void deserialize(const string& s, map_str_str_t & data); -int map_to_zmsg(const map_str_str_t & data, zmq_msg_t &msg); +template +int map_to_zmsg(const Map & data, zmq_msg_t &msg); + +template +void zmsg_to_map(zmq_msg_t &msg, Map &data); + + +/* + * events are published as two part zmq message. + * First part only has the event source, so receivers could + * filter by source. + * + * Second part contains map as defined in internal_event_t. + * The map is serialized and sent as string. + * + */ +/* + * This is data going over wire and using cache. So be conservative + * on names + */ +#define EVENT_STR_DATA "d" +#define EVENT_RUNTIME_ID "r" +#define EVENT_SEQUENCE "s" + +typedef map internal_event_t; + +/* Sequence is converted to string in message */ +tyepdef uint32_t sequence_t; +tyepdef string runtime_id_t; + +internal_event_t internal_event_ref = { + { EVENT_STR_DATA, "" }, + { EVENT_RUNTIME_ID, "" }, + { EVENT_SEQUENCE, "" } }; + +/* ZMQ message part 2 contains serialized version of internal_event_t */ +typedef string events_data_type_t +typedef vector events_data_lst_t; + + +template +zmq_read_part(void *sock, int flag, int &more, p data) +{ + zmq_msg_t msg; + + more = 0; + zmq_msg_init(&msg); + int rc = zmq_msg_recv(&msg, sock, flag); + + if (rc != -1) { + size_t more_size = sizeof (more); + + zmsg_to_map(msg, data); + + rc = zmq_getsockopt (m_socket, ZMQ_RCVMORE, &more, &more_size); + + } + zmq_msg_close(&msg); + + return rc; +} + + +template +zmq_send_part(void *sock, int flag, p data) +{ + zmq_msg_t msg; + + int rc = map_to_zmsg(data, msg); + RET_ON_ERR(rc == 0, "Failed to map to zmsg"); + + rc = zmq_msg_send (&msg, sock, flag); + RET_ON_ERR(rc != -1, "Failed to send part"); + + rc = 0; +out: + zmq_msg_close(&msg); + return rc; +} + +template +int +zmq_message_send(void *sock, p1 pt1, p2 pt2) +{ + int rc = zmq_send_part(sock, pt2.empty() ? 0 : ZMQ_SNDMORE, pt1); + + if (rc == 0) { + rc = zmq_send_part(sock, 0, pt2); + } + return rc; +} + + +template +int +zmq_message_read(void *sock, int flag, p1 pt1, p2 pt2) +{ + int more = 0, rc; + + rc = zmq_read_part(sock, flag, more, pt1); + RET_ON_ERR(rc == 0, "Failed to read part1"); + RET_ON_ERR(more, "Expect 2 parts"); + + rc = zmq_read_part(sock, 0, more, pt2); + RET_ON_ERR(rc == 0, "Failed to read part1"); + RET_ON_ERR(!more, "Don't expect more than 2 parts"); + +out: + return rc; +} + -void zmsg_to_map(zmq_msg_t &msg, map_str_str_t & data); -#define u32_to_s(u32) std::to_string(u32) -#define s_to_u32(s, u32) { stringstream _ss(s); s >> u32;} diff --git a/common/events_pi.h b/common/events_pi.h index 13528c135..2c108d43a 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -1,8 +1,9 @@ /* - * Private header file + * Private header file used by events API implementation. * Required to run white box testing via unit tests. */ #include +#include #include #include #include @@ -18,33 +19,30 @@ using namespace std; -/* - * events are published as two part zmq message. - * First part only has the event source, so receivers could - * filter by source. - * - * Second part contains map of - * internal_event_t; - -tyepdef string runtime_id_t; - -internal_event_t internal_event_ref = { - { EVENT_STR_DATA, "" }, - { EVENT_RUNTIME_ID, "" }, - { EVENT_SEQUENCE, "" } }; /* Base class for publisher & subscriber */ class events_base { public: virtual ~events_base() = default; + + static sequence_t str_to_seq(const string s) + { + stringstream ss(s); + sequence_t seq; + + ss >> seq; + + return seq; + } + + static string seq_to_str(sequence_t seq) + { + stringstream ss(); + ss << seq; + return ss.str(); + } + }; /* @@ -56,36 +54,30 @@ class events_base typedef map< lst_publishers_t; -class EventPublisher : public events_base { +class EventPublisher : public events_base +{ public: - // Track publishers by source & sender, as missed messages - // is tracked per sender by source - // - static lst_publishers_t s_publishers; + EventPublisher(); + + virtual ~EventPublisher(); + + int init(const char *event_source, int block_ms=-1); + + void publish(event_handle_t &handle, const std::string &event_tag, + const event_params_t *params); + private: void *m_zmq_ctx; void *m_socket; event_service m_event_svc; - /* Event source in msg to be sent as part 1 of multi-part */ - zmq_msg_t m_zmsg_source; string m_event_source; runtime_id_t m_runtime_id; - uint32_t m_sequence; + sequence_t m_sequence; bool m_init; - - EventPublisher(); - - int init(const char *event_source, int block_ms=-1); - - virtual ~EventPublisher(); - - void publish(event_handle_t &handle, const std::string &event_tag, - const event_params_t *params); - }; /* @@ -99,54 +91,42 @@ class EventPublisher : public events_base { class EventSubscriber : public events_base { public: - - void *m_zmq_ctx; - void *m_socket; - - // Indices are tracked per sendefr & source. - // - map m_indices; - - // Cumulative missed count across all subscribed sources. - // - uint64_t m_missed_cnt; - - EventSubscriber(const event_subscribe_sources_t *subs_sources); + EventSubscriber(); + + int init(bool use_cache=false, + const event_subscribe_sources_t *subs_sources); virtual ~EventSubscriber(); - bool do_receive(map_str_str_t *data); + int event_receive(event_str_t &event, int &missed_cnt); - bool validate_meta(const map_str_str_t &meta); + private: + void *m_zmq_ctx; + void *m_socket; - index_data_t update_missed(map_str_str_t &meta); + event_service m_event_svc; - void event_receive(event_metadata_t &metadata, event_params_t ¶ms, - unsigned long *missed_count = NULL); -}; + bool m_init; + bool m_cache_read; -class EventProxy -{ - public: - void *m_ctx; - void *m_rep; - void *m_frontend; - void *m_backend; - bool m_init_success; + /* + * Sequences tracked by sender for a source, or in other + * words by runtime id. + */ + typedef struct _evt_info { + _evt_info() : epoch_secs(0), seq(0) {}; + _evt_info(s) : epoch_secs(time(nullptr)), seq(s) {}; - std::thread m_req_thread, m_proxy_thread; + time_t epoch_secs; + sequence_t seq; + } evt_info_t; - EventProxy(); + typedef map track_info_t; + track_info_t m_track; - ~EventProxy(); + events_data_lst_t m_from_cache; - int run(void); + void prune_track(); - void run_cache_service(void); - void run_proxy(void); }; -extern EventProxy g_event_proxy; - - - diff --git a/common/events_service.cpp b/common/events_service.cpp index 9124205d2..980d8e312 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -42,7 +42,7 @@ event_service:init_server() int event_service:echo_send(const string s) { - vector l = { s }; + events_data_lst_t l = { s }; return channel_write(EVENT_ECHO, l); @@ -52,7 +52,7 @@ event_service:echo_send(const string s) int event_service::echo_receive(string &outs) { - vector l; + events_data_lst_t l; int code; int rc = channel_read(code, l); @@ -68,11 +68,11 @@ event_service::echo_receive(string &outs) int -event_service::cache_start() +event_service::cache_init() { - int rc = send_recv(EVENT_CACHE_START); + int rc = send_recv(EVENT_CACHE_INIT); if (rc == 0) { - /* To shadow subscribe connect required for cache start */ + /* To shadow subscribe connect required for cache init */ send_recv(EVENT_ECHO); } return rc; @@ -80,91 +80,53 @@ event_service::cache_start() int -event_service::cache_stop() +event_service::cache_start(events_data_lst_t &lst) { - return send_recv(EVENT_CACHE_STOP); + RET_ON_ERR((rc = send_recv(EVENT_CACHE_START, &lst) == 0, + "Failed to send cache start"); +out: + return rc; } int -event_service::cache_read(vector &lst) +event_service::cache_stop() { - return send_recv(EVENT_CACHE_READ, lst); + RET_ON_ERR((rc = send_recv(EVENT_CACHE_STOP) == 0, + "Failed to send cache stop"); +out: + return rc; } int -event_service::channel_read(int &code, vector &data) +event_service::cache_read(events_data_lst_t &lst) { - int more = 0, rc; - size_t more_size = sizeof (more); - - { - zmq_msg_t rcv_code; - - rc = zmq_msg_recv(&rcv_code, m_req_socket, 0); - RET_ON_ERR(rc != -1, "Failed to receive code"); - - zmsg_to_map(rcv_code, code); - zmq_msg_close(&rcv_code); - } - - rc = zmq_getsockopt (m_socket, ZMQ_RCVMORE, &more, &more_size); - RET_ON_ERR(rc == 0, "Failed to get sockopt for read channel"); - - - if (more) { - zmq_msg_t rcv_data; - - rc = zmq_msg_recv(&rcv_data, m_req_socket, 0); - RET_ON_ERR(rc != -1, "Failed to receive data"); - - rc = zmq_getsockopt (m_socket, ZMQ_RCVMORE, &more, &more_size); - RET_ON_ERR(rc == 0, "Failed to get sockopt for read channel"); - RET_ON_ERR(!more, "Expecting more than 2 parts"); - - zmsg_to_map(rcv_data, data); - zmq_msg_close(&rcv_data); - } + RET_ON_ERR((rc = send_recv(EVENT_CACHE_READ, &lst) == 0, + "Failed to send cache read"); out: - reurn rc; + return rc; } int -event_service::channel_write(int code, const vector &data) +event_service::channel_read(int &code, events_data_lst_t &data) { - zmq_msg_t msg_req, msg_data; - int flag = 0; - - int rc = map_to_zmsg(code,msg_req); - RET_ON_ERR(rc == 0, "Failed int (%d) to msg", code); - - if (!data.empty()) { - rc = map_to_zmsg(code, msg_data); - RET_ON_ERR(rc == 0, "Failed vec (%d) to msg", data.size()); - flag = ZMQ_SNDMORE; - } - - rc = zmq_msg_send (&msg_req, m_socket, flag); - RET_ON_ERR(rc == 0, "Failed to send code"); + return zmq_message_read(m_socket, code, data); +} - if (flag != 0) { - rc = zmq_msg_send (&msg_data, m_socket, 0); - RET_ON_ERR(rc == 0, "Failed to send data"); - } -out: - zmq_msg_close(&msg_req); - zmq_msg_close(&msg_data); - return rc; +int +event_service::channel_write(int code, const events_data_lst_t &data) +{ + return zmq_message_send(m_socket, 0, code, data); } int -event_service::send_recv(int code, vector *p = NULL) +event_service::send_recv(int code, events_data_lst_t *p = NULL) { - vector l; + events_data_lst_t l; int resp; if(p == NULL) { diff --git a/common/events_service.h b/common/events_service.h index f943dd05d..4e2eb791b 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -3,6 +3,13 @@ /* + * The eventd runs an event service that supports caching & miscellaneous + * as required by events API. + * + * This header lists the services provided, + * + * These services are only used by events API. + * * All the services uses REQ/REP pattern between caller * centralized event service. The return code is provided * by service in its reply. @@ -10,26 +17,26 @@ * event_request goes as single part message carrying event_req_t, * unless there is data associated. * - * Both req & resp are either single or multi part. In case of no + * Both req & resp are either single or two part. In case of no * data associated, it is just request code or response return value in one part. * In case of data, it comes in seccond part. * - * Type of data is as decided by request. + * Type of data is one or multiple strings, which is sent as serialized vector + * of strings. events_data_lst_t * - * In case of echo, part2 is the string as provided in the request. + * In case of echo, part2 is the vector of single string as provided in the request. * * The read returns as serialized vector of ZMQ messages, in part2. */ typedef enum { + EVENT_CACHE_INIT, EVENT_CACHE_START, EVENT_CACHE_STOP, EVENT_CACHE_READ, EVENT_ECHO } event_req_type_t; -typedef string events_data_type_t; -typedef vector events_data_lst_t; /* * internal service init & APIs for read & write @@ -47,6 +54,11 @@ class event_service { ~event_service() { close(); } + /* + * Block helps setting timeout for any read + * Publish clients that choose to block specify the duration + * + */ int init_client(void *zmq_ctx, int block_ms = -1); int init_server(void *zmq_ctx); @@ -61,18 +73,36 @@ class event_service { */ + /* + * Called to init caching events + * + * This is transparently called by events_deinit_subscriber, if cache service + * was enabled. This simply triggers a connect request and does not start + * reading yet. + * + * return: + * 0 - On success. + * 1 - Already running + * -1 - On failure. + */ + int cache_init(); + /* * Called to start caching events * * This is transparently called by events_deinit_subscriber, if cache service - * was enabled. + * was enabled after init, with excess events it had in its cache. + * The caching service uses this as initial/startup stock. + * + * input: + * lst - i/p events from caller's cache. * * return: * 0 - On success. * 1 - Already running * -1 - On failure. */ - int cache_start(); + int cache_start(events_data_lst_t &lst); /* * Called to stop caching events @@ -93,7 +123,7 @@ class event_service { * This is transparently called by event_receive, if cache service * is enabled. * Each event is received as 2 parts. First part is more a filter for - * hence dropped. The second part is returned as string. + * hence dropped. The second part is returned as string events_data_type_t. * The string is the serialized form of internal_event_t. * * An empty o/p implies no more. @@ -101,8 +131,6 @@ class event_service { * Internal details: * * Cache service caches all events until buffer overflow - * During receive using sequence+runtime Id, it keeps the count - * of missed to receive. * * Upon overflow, it creates a separate cache, where it keeps only * the last event received per runtime ID. @@ -112,7 +140,8 @@ class event_service { * events read from subscription channel & as well from cache. * * output: - * lst_msgs + * lst - A set of events, with a max cap. + * Hence multiple reads may be required to read all. * * return: * 0 - On success. Either stopped or none to stop. @@ -194,9 +223,6 @@ class event_service { */ int send_recv(int code, events_data_lst_t *p = NULL); - - - /* * de-init/close service */ From d130b84e342b79cb9cea6b65531fcafd2dbc2a0c Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 20 May 2022 00:33:35 +0000 Subject: [PATCH 07/97] self review update --- common/events_common.cpp | 59 ----------------------------- common/events_common.h | 80 ++++++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 75 deletions(-) diff --git a/common/events_common.cpp b/common/events_common.cpp index dda01620b..f2083599d 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -1,8 +1,4 @@ #include "events_common.h" -#include -#include -#include -#include int zerrno = 0; @@ -81,58 +77,3 @@ get_timestamp() return ss.str(); } - -/* - * Way to serialize map or vector - * boost::archive::text_oarchive could be used to archive any struct/class - * but that class needs some additional support, that declares - * boost::serialization::access as private friend and couple more tweaks - * std::map inherently supports serialization - */ -template -const string -serialize(const Map& data) -{ - std::stringstream ss; - boost::archive::text_oarchive oarch(ss); - oarch << data; - return ss.str(); -} - -template -void -deserialize(const string& s, Map& data) -{ - std::stringstream ss; - ss << s; - boost::archive::text_iarchive iarch(ss); - iarch >> data; - return; -} - - -template -int -map_to_zmsg(const Map& data, zmq_msg_t &msg) -{ - string s = serialize(data); - - int rc = zmq_msg_init_size(&msg, s.size()); - if (rc == 0) { - strncpy((char *)zmq_msg_data(&msg), s.c_str(), s.size()); - } - return rc; -} - - -template -void -zmsg_to_map(zmq_msg_t &msg, Map& data) -{ - string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); - deserialize(s, data); -} - - - - diff --git a/common/events_common.h b/common/events_common.h index af76e0089..fb237757b 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -10,6 +10,10 @@ #include "json.hpp" #include "zmq.h" #include +#include +#include +#include +#include #include "logger.h" #include "events.h" @@ -20,12 +24,18 @@ using namespace chrono; extern int errno; extern int zerrno; +/* + * Max count of possible concurrent event publishers + * A rough estimate only, more as a guideline than strict. + * So this does not limit any usage + */ +#define MAX_PUBLISHERS_COUNT 1000 #define RET_ON_ERR(res, msg, ...)\ if (!(res)) {\ int e = errno; \ zerrno = zmq_errno(); \ - string fmt = "errno:%d zmq_errno:%d " + msg; \ + string fmt = string("errno:%d zmq_errno:%d ") + msg; \ SWSS_LOG_ERROR(fmt.c_str(), e, zerrno, ##__VA_ARGS__); \ goto out; } @@ -64,9 +74,9 @@ T get_config_data(const string key, T def) return def; } else { - stringstream ss(get_config(key)); - T v; + stringstream ss(s); + ss >> v; return v; @@ -78,15 +88,56 @@ string get_config(const string key); const string get_timestamp(); -const string serialize(const map_str_str_t & data); +/* + * Way to serialize map or vector + * boost::archive::text_oarchive could be used to archive any struct/class + * but that class needs some additional support, that declares + * boost::serialization::access as private friend and couple more tweaks + * std::map inherently supports serialization + */ +template +const string +serialize(const Map& data) +{ + std::stringstream ss; + boost::archive::text_oarchive oarch(ss); + oarch << data; + return ss.str(); +} + +template +void +deserialize(const string& s, Map& data) +{ + std::stringstream ss; + ss << s; + boost::archive::text_iarchive iarch(ss); + iarch >> data; + return; +} -void deserialize(const string& s, map_str_str_t & data); template -int map_to_zmsg(const Map & data, zmq_msg_t &msg); +int +map_to_zmsg(const Map& data, zmq_msg_t &msg) +{ + string s = serialize(data); + + int rc = zmq_msg_init_size(&msg, s.size()); + if (rc == 0) { + strncpy((char *)zmq_msg_data(&msg), s.c_str(), s.size()); + } + return rc; +} + template -void zmsg_to_map(zmq_msg_t &msg, Map &data); +void +zmsg_to_map(zmq_msg_t &msg, Map& data) +{ + string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); + deserialize(s, data); +} /* @@ -168,7 +219,7 @@ zmq_message_send(void *sock, p1 pt1, p2 pt2) { int rc = zmq_send_part(sock, pt2.empty() ? 0 : ZMQ_SNDMORE, pt1); - if (rc == 0) { + if ((rc == 0) && (!pt2.empty())) { rc = zmq_send_part(sock, 0, pt2); } return rc; @@ -183,17 +234,14 @@ zmq_message_read(void *sock, int flag, p1 pt1, p2 pt2) rc = zmq_read_part(sock, flag, more, pt1); RET_ON_ERR(rc == 0, "Failed to read part1"); - RET_ON_ERR(more, "Expect 2 parts"); - rc = zmq_read_part(sock, 0, more, pt2); - RET_ON_ERR(rc == 0, "Failed to read part1"); - RET_ON_ERR(!more, "Don't expect more than 2 parts"); + if (more) { + rc = zmq_read_part(sock, 0, more, pt2); + RET_ON_ERR(rc == 0, "Failed to read part1"); + RET_ON_ERR(!more, "Don't expect more than 2 parts"); + } out: return rc; } - - - - From 63db87ac3f25a5c002bf842013ed5261fda9a5e0 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Sat, 21 May 2022 00:22:46 +0000 Subject: [PATCH 08/97] partial compile --- common/Makefile.am | 2 ++ common/events.cpp | 68 ++++++++++++++++++++++++----------- common/events.h | 75 ++++++++++++++++++++++++++------------- common/events_common.h | 48 ++++++++++++++----------- common/events_pi.h | 15 ++++---- common/events_service.cpp | 50 ++++++++++++++------------ common/events_service.h | 62 +++++++++++++++++++++++++------- 7 files changed, 214 insertions(+), 106 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index 6f0fe413c..f399839c8 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -29,6 +29,8 @@ endif libswsscommon_la_SOURCES = \ events_common.cpp \ + events_service.cpp \ + events.cpp \ logger.cpp \ redisreply.cpp \ configdb.cpp \ diff --git a/common/events.cpp b/common/events.cpp index eec01b18c..4eebc79bd 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -1,19 +1,32 @@ #include "events_pi.h" +/* + * Publisher use echo service and subscriber uses cache service + * The eventd process runs this service, which could be down + * All service interactions being async, a timeout is required + * not to block forever on read. + * + * The unit is in milliseconds (in sync with ZMQ_RCVTIMEO of + * zmq_setsockopt. + */ + +#define EVENTS_SERVICE_TIMEOUT_MILLISECS 200 + /* * Track created publishers to avoid duplicates * As we track missed event count by publishing instances, avoiding * duplicates helps reduce load. */ + typedef map lst_publishers_t; lst_publishers_t s_publishers; -EventPublisher::EventPublisher(const string source) : +EventPublisher::EventPublisher() : m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0), m_init(false) { } -int EventPublisher::init(const string event_source, int block_ms) +int EventPublisher::init(const string event_source) { m_zmq_ctx = zmq_ctx_new(); m_socket = zmq_socket (m_zmq_ctx, ZMQ_PUB); @@ -26,7 +39,11 @@ int EventPublisher::init(const string event_source, int block_ms) // Any message published before connection establishment is dropped. // event_service m_event_svc; - rc = m_event_svc.init_client(block_ms); + /* + * Event service could be down. So have a timeout. + * + */ + rc = m_event_svc.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MILLISECS); RET_ON_ERR (rc == 0, "Failed to init event service"); rc = m_event_svc.echo_send("hello"); @@ -57,7 +74,7 @@ EventPublisher::event_publish(const string tag, const event_params_t *params) string s; /* Failure is no-op; The eventd service my be down - * NOTE: This call atmost blocks for block_ms milliseconds + * NOTE: This call atmost blocks for EVENTS_SERVICE_TIMEOUT_MILLISECS * as provided in publisher init. */ m_event_service.echo_receive(s); @@ -82,11 +99,11 @@ EventPublisher::event_publish(const string tag, const event_params_t *params) event_data[EVENT_RUNTIME_ID] = m_runtime_id; event_data[EVENT_SEQUENCE] = seq_to_str(m_sequence); - return zmq_message_send(m_event_source, event_data); + return zmq_message_send(m_socket, m_event_source, event_data); } event_handle_t -events_init_publisher(const string event_source, int block_millisecs) +events_init_publisher(const string event_source) { event_handle_t ret = NULL; lst_publishers_t::iterator it = s_publishers.find(event_source); @@ -97,7 +114,7 @@ events_init_publisher(const string event_source, int block_millisecs) else { EventPublisher *p = new EventPublisher(); - int rc = p->init(event_source, block_millisecs); + int rc = p->init(event_source); if (rc != 0) { delete p; @@ -132,10 +149,10 @@ event_publish(event_handle_t handle, const string tag, const event_params_t *par { for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { if (it->second == handle) { - it->second->event_publish(tag, params); - break; + return it->second->event_publish(tag, params); } } + return -1; } @@ -179,7 +196,9 @@ EventSubscriber::~EventSubscriber() break; } events.push_back(evt_str); - if(chrono::steady_clock::now() - start > chrono::seconds(2)) + chrono::steady_clock::timepoint now = chrono::steady_clock::now(); + if (chrono::duration_cast(now - start) > + CACHE_DRAIN_IN_MILLISECS) break; } @@ -223,12 +242,9 @@ EventSubscriber::init(bool use_cache, const event_subscribe_sources_t *subs_sour } if (use_cache) { - rc = m_event_svc.init_client(m_zmq_ctx); + rc = m_event_svc.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MILLISECS); RET_ON_ERR(rc == 0, "Fails to init the service"); - /* Shadow the cache SUBS connect request, as it is async */ - m_event_svc.send_recv(EVENT_ECHO); - if (m_event_svc.cache_stop() == 0) { // Stopped an active cache m_cache_read = true; @@ -261,10 +277,12 @@ EventSubscriber::prune_track() int -EventSubscriber::event_receive(event_str_t &event, int &missed_cnt) +EventSubscriber::event_receive(string &&key, event_params_t ¶ms, int &missed_cnt) { - event.clear(); - while (event.empty()) { + key.clear(); + event_params_t().swap(params); + + while (key.empty()) { internal_event_t event_data; int rc = 0; @@ -303,7 +321,16 @@ EventSubscriber::event_receive(event_str_t &event, int &missed_cnt) } } if (missed_cnt >= 0) { - event = event_data[EVENT_STR_DATA]; + map_str_str_t ev; + + deserialize(event_data[EVENT_STR_DATA], ev); + RET_ON_ERR(ev.size() == 1, "Expect string (%s) deserialize to one key", + event_data[EVENT_STR_DATA].c_str()); + + key = ev.begin()->first; + + deserialize(ev.begin()->second, params); + } } out: @@ -345,10 +372,11 @@ events_deinit_subscriber(event_handle_t &handle) int -event_receive(event_handle_t handle, event_str_t &event, int &missed_cnt) +event_receive(event_handle_t handle, string &key, + event_params_t ¶ms, int &missed_cnt) { if ((handle == s_subscriber) && (s_subscriber != NULL)) { - return s_subscriber->event_receive(event, missed_cnt); + return s_subscriber->event_receive(key, params, missed_cnt); } return -1; } diff --git a/common/events.h b/common/events.h index 64639b09b..8af45a904 100644 --- a/common/events.h +++ b/common/events.h @@ -1,3 +1,6 @@ +#ifndef _EVENTS_H +#define _EVENTS_H + /* * Events library * @@ -30,20 +33,12 @@ typedef void* event_handle_t; * returned by this call is tagged with this source, transparently. The receiver * could subscribe with this source as filter. * - * block_millisecs - - * Block either until publisher connects successfully or timeout - * whichever earlier. - * 0 - No blocling. - * -1 - Block until connected. - * N - Count in milli seconds to wait. - * NOTE: The connection is to eventd service, which could be down. * Return * Non NULL handle * NULL on failure */ -event_handle_t events_init_publisher(std::string event_source, - int block_millisecs); +event_handle_t events_init_publisher(std::string event_source); /* * De-init/free the publisher @@ -65,7 +60,7 @@ typedef std::map event_params_t; /* * timestamp param name */ -const string event_ts("timestamp"); +const std::string event_ts("timestamp"); /* * Publish an event @@ -78,7 +73,7 @@ const string event_ts("timestamp"); * the running instance of a publisher and other a running sequence * starting from 0, which is local to this runtime-id. * - * The receiver API keep next last received number for each runtime id + * The receiver API keep last received number for each runtime id * and use this info to compute missed event count upon next event. * * input: @@ -97,8 +92,11 @@ const string event_ts("timestamp"); * The timestamp should be per rfc3339 * e.g. "2022-08-17T02:39:21.286611Z" * + * return: + * 0 - On success + * -1 - On failure. */ -void event_publish(event_handle_t handle, const std::string event_tag, +int event_publish(event_handle_t handle, const std::string event_tag, const event_params_t *params=NULL); @@ -112,8 +110,8 @@ typedef std::vector event_subscribe_sources_t; * Input: * use_cache * When set to true, it will make use of the cache service transparently. - * The cache service caches events during session down time (last deinit to this - * init call). + * The cache service caches events during session down time. The deinit + * start the caching and init call stops the caching. * * lst_subscribe_sources_t * List of subscription sources of interest. @@ -138,26 +136,37 @@ event_handle_t events_init_subscriber(bool use_cache=false, */ void events_deinit_subscriber(event_handle_t &handle); -/* - * Received event as JSON string as - * < YANG path of schema >: { - * event_params_t - * } - */ -typedef std::string event_str_t; - /* * Receive an event. * A blocking call. * * This API maintains an expected sequence number and use the received - * sequence in event to compute missed events count. + * sequence in event to compute missed events count. The missed count + * set of events missed from this sender. + * + * Received event: + * It is a form of JSON struct, with a single key and + * params as value. The key is : and params is as per schema description for that event. + * + * e.g. + * { "sonic-events-bgp:bgp-state": { + * "ip": "100.126.188.90", + * "status": "down", + * "timestamp": "2022-08-17T02:39:21.286611Z" + * } + * } * * input: * handle - As obtained from events_init_subscriber * * output: - * event - Received event. + * key : + * YANG path as : + * + * params: + * Parms associated. * * missed_cnt: * Count of missed events from this sender, before this event. Sum of @@ -168,5 +177,21 @@ typedef std::string event_str_t; * -1 - On failure. The handle is not valid. * */ -int event_receive(event_handle_t handle, event_str_t &event, int &missed_cnt); +int event_receive(event_handle_t handle, std::string &key, + event_params_t ¶ms, int &missed_cnt); + + +/* + * Cache drain timeout. + * + * When de-init is called, it calls stop cache service. + * But before this point, there could be events received in zmq's + * local cache pending read and those that arrived since last read. + * These events will not be seen by cache service. + * So read those off and give it to cache service as starting stock. + * As we don't have a clue on count in zmq's cache, read in non-block + * mode for a period. + */ +#define CACHE_DRAIN_IN_MILLISECS 1000 +#endif /* !_EVENTS_H */ diff --git a/common/events_common.h b/common/events_common.h index fb237757b..c3d623fe5 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -1,3 +1,5 @@ +#ifndef _EVENTS_COMMON_H +#define _EVENTS_COMMON_H /* * common APIs used by events code. */ @@ -27,16 +29,19 @@ extern int zerrno; /* * Max count of possible concurrent event publishers * A rough estimate only, more as a guideline than strict. + SWSS_LOG_ERROR(fmt.c_str(), e, zerrno __VA_OPT__(,) __VA_ARGS__); \ * So this does not limit any usage */ #define MAX_PUBLISHERS_COUNT 1000 + +/* TODO: Combine two SWSS_LOG_ERROR into one */ #define RET_ON_ERR(res, msg, ...)\ if (!(res)) {\ int e = errno; \ zerrno = zmq_errno(); \ - string fmt = string("errno:%d zmq_errno:%d ") + msg; \ - SWSS_LOG_ERROR(fmt.c_str(), e, zerrno, ##__VA_ARGS__); \ + SWSS_LOG_ERROR(msg, ##__VA_ARGS__); \ + SWSS_LOG_ERROR("last:errno=%d zerr=%d", e, zerrno); \ goto out; } #define ERR_CHECK(res, ...) {\ @@ -64,8 +69,10 @@ typedef map map_str_str_t; /* init config from file */ void read_init_config(const char *fname); -/* Provide a key for configurable entity */ -template +/* Read config entry for a key */ +string get_config(const string key); + +template T get_config_data(const string key, T def) { string s(get_config(key)); @@ -84,8 +91,6 @@ T get_config_data(const string key, T def) } -string get_config(const string key); - const string get_timestamp(); /* @@ -160,8 +165,8 @@ zmsg_to_map(zmq_msg_t &msg, Map& data) typedef map internal_event_t; /* Sequence is converted to string in message */ -tyepdef uint32_t sequence_t; -tyepdef string runtime_id_t; +typedef uint32_t sequence_t; +typedef string runtime_id_t; internal_event_t internal_event_ref = { { EVENT_STR_DATA, "" }, @@ -169,12 +174,13 @@ internal_event_t internal_event_ref = { { EVENT_SEQUENCE, "" } }; /* ZMQ message part 2 contains serialized version of internal_event_t */ -typedef string events_data_type_t +typedef string events_data_type_t; typedef vector events_data_lst_t; -template -zmq_read_part(void *sock, int flag, int &more, p data) +template +int +zmq_read_part(void *sock, int flag, int &more, DT data) { zmq_msg_t msg; @@ -187,7 +193,7 @@ zmq_read_part(void *sock, int flag, int &more, p data) zmsg_to_map(msg, data); - rc = zmq_getsockopt (m_socket, ZMQ_RCVMORE, &more, &more_size); + rc = zmq_getsockopt (sock, ZMQ_RCVMORE, &more, &more_size); } zmq_msg_close(&msg); @@ -196,16 +202,17 @@ zmq_read_part(void *sock, int flag, int &more, p data) } -template -zmq_send_part(void *sock, int flag, p data) +template +int +zmq_send_part(void *sock, int flag, DT data) { zmq_msg_t msg; int rc = map_to_zmsg(data, msg); - RET_ON_ERR(rc == 0, "Failed to map to zmsg"); + RET_ON_ERR(rc == 0, "Failed to map to zmsg %d", 5); rc = zmq_msg_send (&msg, sock, flag); - RET_ON_ERR(rc != -1, "Failed to send part"); + RET_ON_ERR(rc != -1, "Failed to send part %d", 5); rc = 0; out: @@ -213,9 +220,9 @@ zmq_send_part(void *sock, int flag, p data) return rc; } -template +template int -zmq_message_send(void *sock, p1 pt1, p2 pt2) +zmq_message_send(void *sock, P1 pt1, P2 pt2) { int rc = zmq_send_part(sock, pt2.empty() ? 0 : ZMQ_SNDMORE, pt1); @@ -226,9 +233,9 @@ zmq_message_send(void *sock, p1 pt1, p2 pt2) } -template +template int -zmq_message_read(void *sock, int flag, p1 pt1, p2 pt2) +zmq_message_read(void *sock, int flag, P1 pt1, P2 pt2) { int more = 0, rc; @@ -245,3 +252,4 @@ zmq_message_read(void *sock, int flag, p1 pt1, p2 pt2) return rc; } +#endif /* !_EVENTS_COMMON_H */ diff --git a/common/events_pi.h b/common/events_pi.h index 2c108d43a..fe248fed7 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -1,3 +1,5 @@ +#ifndef _EVENTS_SERVICE_H +#define _EVENTS_SERVICE_H /* * Private header file used by events API implementation. * Required to run white box testing via unit tests. @@ -38,7 +40,7 @@ class events_base static string seq_to_str(sequence_t seq) { - stringstream ss(); + stringstream ss; ss << seq; return ss.str(); } @@ -52,8 +54,6 @@ class events_base * */ -typedef map< lst_publishers_t; - class EventPublisher : public events_base { public: @@ -61,7 +61,7 @@ class EventPublisher : public events_base virtual ~EventPublisher(); - int init(const char *event_source, int block_ms=-1); + int init(const string event_source); void publish(event_handle_t &handle, const std::string &event_tag, const event_params_t *params); @@ -94,11 +94,11 @@ class EventSubscriber : public events_base EventSubscriber(); int init(bool use_cache=false, - const event_subscribe_sources_t *subs_sources); + const event_subscribe_sources_t *subs_sources=NULL); virtual ~EventSubscriber(); - int event_receive(event_str_t &event, int &missed_cnt); + int event_receive(string &key, event_params_t ¶ms, int &missed_cnt); private: void *m_zmq_ctx; @@ -115,7 +115,7 @@ class EventSubscriber : public events_base */ typedef struct _evt_info { _evt_info() : epoch_secs(0), seq(0) {}; - _evt_info(s) : epoch_secs(time(nullptr)), seq(s) {}; + _evt_info(sequence_t s) : epoch_secs(time(nullptr)), seq(s) {}; time_t epoch_secs; sequence_t seq; @@ -130,3 +130,4 @@ class EventSubscriber : public events_base }; +#endif /* !_EVENTS_SERVICE_H */ diff --git a/common/events_service.cpp b/common/events_service.cpp index 980d8e312..560432d79 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -2,45 +2,45 @@ int -event_service:init_client(int block_ms) +event_service::init_client(void *zmq_ctx, int block_ms) { int rc = -1; - void *sock = zmq_socket (m_zmq_ctx, ZMQ_REQ); + void *sock = zmq_socket (zmq_ctx, ZMQ_REQ); RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REQ socket"); - rc = zmq_connect (sock, get_config(REQ_REP_END_KEY)); - RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY)); + rc = zmq_connect (sock, get_config(REQ_REP_END_KEY).c_str()); + RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY).c_str()); // Set read timeout. // rc = zmq_setsockopt (sock, ZMQ_RCVTIMEO, &block_ms, sizeof (block_ms)); - RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY)); + RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY).c_str()); m_socket = sock; out: - return ret; + return rc; } int -event_service:init_server() +event_service::init_server(void *zmq_ctx) { int rc = -1; - void *sock = zmq_socket (m_zmq_ctx, ZMQ_REP); + void *sock = zmq_socket (zmq_ctx, ZMQ_REP); RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REP socket"); - rc = zmq_bind (sock, get_config(REQ_REP_END_KEY)); - RET_ON_ERR(rc == 0, "Failed to bind to %s", get_config(REQ_REP_END_KEY)); + rc = zmq_bind (sock, get_config(REQ_REP_END_KEY).c_str()); + RET_ON_ERR(rc == 0, "Failed to bind to %s", get_config(REQ_REP_END_KEY).c_str()); m_socket = sock; out: - return ret; + return rc; } int -event_service:echo_send(const string s) +event_service::echo_send(const string s) { events_data_lst_t l = { s }; @@ -59,7 +59,8 @@ event_service::echo_receive(string &outs) RET_ON_ERR(rc == 0, "failing to read echo"); RET_ON_ERR (code == 0, "echo receive resp %d not 0", code); - RET_ON_ERR (l.size() == 1, "echo received resp size %d is not 1", l.size()); + RET_ON_ERR (l.size() == 1, "echo received resp size %d is not 1", + (int)l.size()); outs = l[0]; out: @@ -82,7 +83,9 @@ event_service::cache_init() int event_service::cache_start(events_data_lst_t &lst) { - RET_ON_ERR((rc = send_recv(EVENT_CACHE_START, &lst) == 0, + int rc; + + RET_ON_ERR((rc = send_recv(EVENT_CACHE_START, &lst) == 0), "Failed to send cache start"); out: return rc; @@ -92,7 +95,9 @@ event_service::cache_start(events_data_lst_t &lst) int event_service::cache_stop() { - RET_ON_ERR((rc = send_recv(EVENT_CACHE_STOP) == 0, + int rc; + + RET_ON_ERR((rc = send_recv(EVENT_CACHE_STOP) == 0), "Failed to send cache stop"); out: return rc; @@ -102,7 +107,9 @@ event_service::cache_stop() int event_service::cache_read(events_data_lst_t &lst) { - RET_ON_ERR((rc = send_recv(EVENT_CACHE_READ, &lst) == 0, + int rc; + + RET_ON_ERR((rc = send_recv(EVENT_CACHE_READ, &lst) == 0), "Failed to send cache read"); out: return rc; @@ -112,19 +119,19 @@ event_service::cache_read(events_data_lst_t &lst) int event_service::channel_read(int &code, events_data_lst_t &data) { - return zmq_message_read(m_socket, code, data); + return zmq_message_read(m_socket, 0, code, data); } int event_service::channel_write(int code, const events_data_lst_t &data) { - return zmq_message_send(m_socket, 0, code, data); + return zmq_message_send(m_socket, code, data); } int -event_service::send_recv(int code, events_data_lst_t *p = NULL) +event_service::send_recv(int code, events_data_lst_t *p) { events_data_lst_t l; int resp; @@ -147,10 +154,9 @@ event_service::send_recv(int code, events_data_lst_t *p = NULL) } -int +void event_service::close_service() { - if (m_socket = NULL) { zmq_close(m_socket); m_socket = NULL; } - return 0; + if (m_socket == NULL) { zmq_close(m_socket); m_socket = NULL; } } diff --git a/common/events_service.h b/common/events_service.h index 4e2eb791b..b88c9ad09 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -8,7 +8,7 @@ * * This header lists the services provided, * - * These services are only used by events API. + * These services are only used by events API internally. * * All the services uses REQ/REP pattern between caller * centralized event service. The return code is provided @@ -52,12 +52,31 @@ class event_service { public: event_service(): m_socket(NULL) {} - ~event_service() { close(); } + ~event_service() { close_service(); } /* - * Block helps setting timeout for any read + * Init the service for client or server. + * The client uses REQ socket & connects. + * The server uses REP socket & bind. + * + * Block helps setting timeout for any read. + * Publishing clients try ECHO service send/recv to help shadow + * its async connection to XPUB end point, but the eventd service + * could be down. So having a timeout, helps which will timeout + * recv. * Publish clients that choose to block specify the duration * + * Input: + * zmq_ctx - Context to use + * block_ms + * 0 - Return immediately + * - Count of millisecs to wait for a message. + * -1 - Block until a message is available or any fatal failure. + * + * return: + * 0 - On success + * -1 - On failure. zerrno is set to EAGAIN, if timed out. + * Else appropriate error code is set as per zmq_msg_recv. */ int init_client(void *zmq_ctx, int block_ms = -1); @@ -66,6 +85,12 @@ class event_service { /* * Event cache service is singleton service * + * Usage: + * Init - Initiates the connection + * start - Start reading & caching + * stop - Stop reading & disconnect. + * read - Read the cached events. + * * Any duplicate start has no impact. * The cached events can be read only upon stop. A read before * stop returns failure. A read w/o a start succeeds with no message. @@ -78,7 +103,8 @@ class event_service { * * This is transparently called by events_deinit_subscriber, if cache service * was enabled. This simply triggers a connect request and does not start - * reading yet. + * reading yet. + * NOTE: ZMQ connects asynchronously. * * return: * 0 - On success. @@ -90,8 +116,8 @@ class event_service { /* * Called to start caching events * - * This is transparently called by events_deinit_subscriber, if cache service - * was enabled after init, with excess events it had in its cache. + * This is transparently called by events_deinit_subscriber after init. + * The deinit call may provide events in its local cache. * The caching service uses this as initial/startup stock. * * input: @@ -156,8 +182,6 @@ class event_service { * it to shadow its connection to zmq proxy's XSUB end. This is * called transparently by events_init_publisher. * - * The service is closed upon failure to send as echo service is one shot only. - * * Input: * s - string to echo. * @@ -187,7 +211,8 @@ class event_service { int echo_receive(string &s); /* - * The underlying read for req/resp from client/server + * The read for req/resp from client/server. The APIs above use this + * to read response and the server use this to read request. * * Input: None * @@ -219,9 +244,22 @@ class event_service { int channel_write(int code, const events_data_lst_t &data); /* - * send and receive helper + * send and receive helper. + * Writes given code & data and reads back data into + * provided events_data_lst_t arg and response read is + * returned. + * + * input: + * code - Request code + * lst - Data to send + * + * output: + * lst - Data read, if any + * + * return: + * Any failure or response code from server. */ - int send_recv(int code, events_data_lst_t *p = NULL); + int send_recv(int code, events_data_lst_t *lst = NULL); /* * de-init/close service @@ -231,7 +269,7 @@ class event_service { /* * Check if service is active */ - bool is_active() { return m_socket != NULL }; + bool is_active() { return m_socket != NULL; }; private: void *m_socket; From cc2bfe57b8424e19d9f6f400493e08597edad66e Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Mon, 23 May 2022 21:13:04 +0000 Subject: [PATCH 09/97] In middle of compilation --- common/events.cpp | 137 ++++++++++++++++++++++++--------------- common/events.h | 2 +- common/events_common.h | 142 +++++++++++++++++++++++++++++++++-------- common/events_pi.h | 8 +-- 4 files changed, 208 insertions(+), 81 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 4eebc79bd..11fd2d18b 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -1,5 +1,13 @@ #include "events_pi.h" +/* + * The uuid_unparse() function converts the supplied UUID uu from + * the binary representation into a 36-byte string (plus trailing + * '\0') of the form 1b4e28ba-2fa1-11d2-883f-0016d3cca427 and stores + * this value in the character string pointed to by out. + */ +#define UUID_STR_SIZE 40 + /* * Publisher use echo service and subscriber uses cache service * The eventd process runs this service, which could be down @@ -18,7 +26,7 @@ * duplicates helps reduce load. */ -typedef map lst_publishers_t; +typedef map lst_publishers_t; lst_publishers_t s_publishers; EventPublisher::EventPublisher() : @@ -31,29 +39,30 @@ int EventPublisher::init(const string event_source) m_zmq_ctx = zmq_ctx_new(); m_socket = zmq_socket (m_zmq_ctx, ZMQ_PUB); - int rc = zmq_connect (m_socket, get_config(XSUB_END_KEY)); - RET_ON_ERR(rc == 0, "Publisher fails to connect %s", get_config(XSUB_END_KEY)); + int rc = zmq_connect (m_socket, get_config(XSUB_END_KEY).c_str()); + RET_ON_ERR(rc == 0, "Publisher fails to connect %s", get_config(XSUB_END_KEY).c_str()); // REQ socket is connected and a message is sent & received, more to // ensure PUB socket had enough time to establish connection. // Any message published before connection establishment is dropped. // - event_service m_event_svc; /* * Event service could be down. So have a timeout. * */ - rc = m_event_svc.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MILLISECS); + rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MILLISECS); RET_ON_ERR (rc == 0, "Failed to init event service"); - rc = m_event_svc.echo_send("hello"); + rc = m_event_service.echo_send("hello"); RET_ON_ERR (rc == 0, "Failed to echo send in event service"); - m_event_source(event_source); + m_event_source = event_source; uuid_t id; + char uuid_str[UUID_STR_SIZE]; uuid_generate(id); - uuid_unparse(id, m_runtime_id); + uuid_unparse(id, uuid_str); + m_runtime_id = string(uuid_str); m_init = true; out: @@ -67,9 +76,12 @@ EventPublisher::~EventPublisher() } -void -EventPublisher::event_publish(const string tag, const event_params_t *params) +int +EventPublisher::publish(const string tag, const event_params_t *params) { + int rc; + internal_event_t event_data; + if (m_event_service.is_active()) { string s; @@ -78,28 +90,41 @@ EventPublisher::event_publish(const string tag, const event_params_t *params) * as provided in publisher init. */ m_event_service.echo_receive(s); + m_event_service.close_service(); } string param_str; - if ((params != NULL) && (param->find(event_ts) != params->end())) { - - param_str = serialize(*params); + event_params_t evt_params; + if (params != NULL) { + if (params->find(event_ts_param) == params->end()) { + evt_params = *params; + evt_params[event_ts_param] = get_timestamp(); + params = &evt_params; + } } else { - event_params_t evt_params = *params; - evt_params[event_ts] = get_timestamp(); - param_str = serialize(evt_params); + evt_params[event_ts_param] = get_timestamp(); + params = &evt_params; } + rc = serialize(*params, param_str); + RET_ON_ERR(rc == 0, "failed to serialize params %s", + map_to_str(*params).c_str()); - map_str_str_t event_str = { { m_event_source + ":" + tag, param_str}}; + { + map_str_str_t event_str_map = { { m_event_source + ":" + tag, param_str}}; - ++m_sequence; - internal_event_t event_data; - event_data[EVENT_STR_DATA] = serialize(event_str); + rc = serialize(event_str_map, event_data[EVENT_STR_DATA]); + RET_ON_ERR(rc == 0, "failed to serialize event str %s", + map_to_str(event_str_map)); + } event_data[EVENT_RUNTIME_ID] = m_runtime_id; + ++m_sequence; event_data[EVENT_SEQUENCE] = seq_to_str(m_sequence); - return zmq_message_send(m_socket, m_event_source, event_data); + rc = zmq_message_send(m_socket, m_event_source, event_data); + RET_ON_ERR(rc == 0, "failed to send for tag %s", tag.c_str()); +out: + return rc; } event_handle_t @@ -121,7 +146,7 @@ events_init_publisher(const string event_source) } else { ret = p; - s_publishers[key] = p; + s_publishers[event_source] = p; } } return ret; @@ -131,7 +156,6 @@ void events_deinit_publisher(event_handle_t &handle) { lst_publishers_t::iterator it; - EventPublisher *pub = NULL; for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { if (it->second == handle) { @@ -144,12 +168,13 @@ events_deinit_publisher(event_handle_t &handle) } -void +int event_publish(event_handle_t handle, const string tag, const event_params_t *params) { - for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { - if (it->second == handle) { - return it->second->event_publish(tag, params); + lst_publishers_t::const_iterator itc; + for(itc=s_publishers.begin(); itc != s_publishers.end(); ++itc) { + if (itc->second == handle) { + return itc->second->publish(tag, params); } } return -1; @@ -175,17 +200,17 @@ EventSubscriber::~EventSubscriber() */ int rc = 0; - if (m_use_cache) { + if (m_event_service.is_active()) { events_data_lst_t events; - rc = m_event_svc.cache_init(); + rc = m_event_service.cache_init(); RET_ON_ERR(rc == 0, "Failed to init the cache"); /* Shadow the cache init request, as it is async */ - m_event_svc.send_recv(EVENT_ECHO); + m_event_service.send_recv(EVENT_ECHO); /* read for 2 seconds in non-block mode, to drain any local cache */ - chrono::steady_clock::timepoint start = chrono::steady_clock::now(); + chrono::steady_clock::time_point start = chrono::steady_clock::now(); while(true) { string source, evt_str; rc = zmq_message_read(m_socket, ZMQ_DONTWAIT, source, evt_str); @@ -196,15 +221,16 @@ EventSubscriber::~EventSubscriber() break; } events.push_back(evt_str); - chrono::steady_clock::timepoint now = chrono::steady_clock::now(); - if (chrono::duration_cast(now - start) > + chrono::steady_clock::time_point now = chrono::steady_clock::now(); + if (chrono::duration_cast(now - start).count() > CACHE_DRAIN_IN_MILLISECS) break; } /* Start cache service with locally read events as initial stock */ - RET_ON_ERR(m_event_svc.cache_start(events) == 0, + RET_ON_ERR(m_event_service.cache_start(events) == 0, "Failed to send cache start"); + m_event_service.close_service(); } out: zmq_close(m_socket); @@ -227,29 +253,28 @@ EventSubscriber::init(bool use_cache, const event_subscribe_sources_t *subs_sour m_socket = zmq_socket (m_zmq_ctx, ZMQ_SUB); - int rc = zmq_connect (m_socket, get_config(XPUB_END_KEY)); - RET_ON_ERR(rc == 0, "Subscriber fails to connect %s", get_config(XPUB_END_KEY)); + int rc = zmq_connect (m_socket, get_config(XPUB_END_KEY).c_str()); + RET_ON_ERR(rc == 0, "Subscriber fails to connect %s", get_config(XPUB_END_KEY).c_str()); if ((subs_sources == NULL) || (subs_sources->empty())) { - rc = zmq_setsockopt(sub_read, ZMQ_SUBSCRIBE, "", 0); + rc = zmq_setsockopt(m_socket, ZMQ_SUBSCRIBE, "", 0); RET_ON_ERR(rc == 0, "Fails to set option"); } else { for (const auto e: *subs_sources) { - rc = zmq_setsockopt(sub_read, ZMQ_SUBSCRIBE, e.c_str(), e.size()); + rc = zmq_setsockopt(m_socket, ZMQ_SUBSCRIBE, e.c_str(), e.size()); RET_ON_ERR(rc == 0, "Fails to set option"); } } if (use_cache) { - rc = m_event_svc.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MILLISECS); + rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MILLISECS); RET_ON_ERR(rc == 0, "Fails to init the service"); - if (m_event_svc.cache_stop() == 0) { + if (m_event_service.cache_stop() == 0) { // Stopped an active cache m_cache_read = true; } - m_use_cache = true; } m_init = true; out: @@ -277,25 +302,26 @@ EventSubscriber::prune_track() int -EventSubscriber::event_receive(string &&key, event_params_t ¶ms, int &missed_cnt) +EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_cnt) { + int rc = 0; key.clear(); event_params_t().swap(params); while (key.empty()) { internal_event_t event_data; - int rc = 0; if (m_cache_read && m_from_cache.empty()) { - m_event_svc.cache_read(m_from_cache); + m_event_service.cache_read(m_from_cache); m_cache_read = !m_from_cache.empty(); } if (!m_from_cache.empty()) { events_data_lst_t::iterator it = m_from_cache.begin(); - deserialize(*it, event_data); + rc = deserialize(*it, event_data); m_from_cache.erase(it); + RET_ON_ERR(rc == 0, "Failed to deserialize message from cache"); } else { @@ -307,9 +333,9 @@ EventSubscriber::event_receive(string &&key, event_params_t ¶ms, int &missed /* Find any missed events for this runtime ID */ missed_cnt = 0; + sequence_t seq = events_base::str_to_seq(event_data[EVENT_SEQUENCE]); track_info_t::iterator it = m_track.find(event_data[EVENT_RUNTIME_ID]); if (it != m_track.end()) { - sequence_t seq = events_base::str_to_seq(event_data[EVENT_SEQUENCE]); /* current seq - last read - 1 == 0 if none missed */ missed_cnt = seq - it->second.seq - 1; it->second = evt_info_t(seq); @@ -323,15 +349,24 @@ EventSubscriber::event_receive(string &&key, event_params_t ¶ms, int &missed if (missed_cnt >= 0) { map_str_str_t ev; - deserialize(event_data[EVENT_STR_DATA], ev); - RET_ON_ERR(ev.size() == 1, "Expect string (%s) deserialize to one key", - event_data[EVENT_STR_DATA].c_str()); + rc = deserialize(event_data[EVENT_STR_DATA], ev); + RET_ON_ERR(rc == 0, "Failed to deserialize %s", + event_data[EVENT_STR_DATA].substr(0, 32).c_str()); + + if (ev.size() != 1) rc = -1; + RET_ON_ERR(rc == 0, "Expect string (%s) deserialize to one key", + event_data[EVENT_STR_DATA].substr(0, 32).c_str()); key = ev.begin()->first; - deserialize(ev.begin()->second, params); + rc = deserialize(ev.begin()->second, params); + RET_ON_ERR(rc == 0, "failed to deserialize params %s", + ev.begin()->second.substr(0, 32).c_str()); } + else { + /* negative value implies duplicate; Possibly seen from cache */ + } } out: return rc; @@ -340,7 +375,7 @@ EventSubscriber::event_receive(string &&key, event_params_t ¶ms, int &missed /* Expect only one subscriber per process */ -EventSubscriber *s_subscriber = NULL; +static EventSubscriber *s_subscriber = NULL; event_handle_t events_init_subscriber(bool use_cache=false, diff --git a/common/events.h b/common/events.h index 8af45a904..8e3732e86 100644 --- a/common/events.h +++ b/common/events.h @@ -60,7 +60,7 @@ typedef std::map event_params_t; /* * timestamp param name */ -const std::string event_ts("timestamp"); +const std::string event_ts_param("timestamp"); /* * Publish an event diff --git a/common/events_common.h b/common/events_common.h index c3d623fe5..49dc24eb7 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "string.h" #include "json.hpp" #include "zmq.h" @@ -38,16 +39,77 @@ extern int zerrno; /* TODO: Combine two SWSS_LOG_ERROR into one */ #define RET_ON_ERR(res, msg, ...)\ if (!(res)) {\ - int e = errno; \ + int _e = errno; \ zerrno = zmq_errno(); \ SWSS_LOG_ERROR(msg, ##__VA_ARGS__); \ - SWSS_LOG_ERROR("last:errno=%d zerr=%d", e, zerrno); \ + SWSS_LOG_ERROR("last:errno=%d zerr=%d", _e, zerrno); \ goto out; } #define ERR_CHECK(res, ...) {\ if (!(res)) \ SWSS_LOG_ERROR(__VA_ARGS__); } +/* helper API to print variable type */ +/* + *Usage: + * const int ci = 0; + * std::cout << type_name() << '\n'; + * + * map l; + * std::cout << type_name() << '\n'; + * + * tt_t t; + * std::cout << type_name() << '\n'; + * std::cout << type_name() << '\n'; + */ + +template std::string type_name(); + +template +std::string +type_name() +{ + typedef typename std::remove_reference::type TR; + std::unique_ptr own + ( + abi::__cxa_demangle(typeid(TR).name(), nullptr, + nullptr, nullptr), + std::free + ); + std::string r = own != nullptr ? own.get() : typeid(TR).name(); + if (std::is_const::value) + r += " const"; + if (std::is_volatile::value) + r += " volatile"; + if (std::is_lvalue_reference::value) + r += "&"; + else if (std::is_rvalue_reference::value) + r += "&&"; + return r; +} + + +template +std::string +get_typename(T &val) +{ + return type_name(); +} + + +template +string +map_to_str(const Map &m) +{ + stringstream _ss; + _ss << "{"; + for (const auto elem: m) { + _ss << "{" << elem.first << "," << elem.second << "}"; + } + _ss << "}"; + return _ss.str(); +} + // Some simple definitions // typedef map map_str_str_t; @@ -101,24 +163,46 @@ const string get_timestamp(); * std::map inherently supports serialization */ template -const string -serialize(const Map& data) +int +serialize(const Map& data, string &s) { - std::stringstream ss; - boost::archive::text_oarchive oarch(ss); - oarch << data; - return ss.str(); + s.clear(); + std::stringstream _ser_ss; + boost::archive::text_oarchive oarch(_ser_ss); + + try { + oarch << data; + s = _ser_ss.str(); + return 0; + } + catch (exception& e) { + stringstream _ser_ex_ss; + + _ser_ex_ss << e.what() << "map data:" << map_to_str(data).substr(0, 32); + SWSS_LOG_ERROR("serialize Failed: %s", _ser_ex_ss.str().c_str()); + return -1; + } } template -void +int deserialize(const string& s, Map& data) { - std::stringstream ss; - ss << s; + std::stringstream ss(s); boost::archive::text_iarchive iarch(ss); - iarch >> data; - return; + + try { + iarch >> data; + return 0; + } + catch (exception& e) { + stringstream _ss_ex; + + _ss_ex << e.what() << "str[0:32]:" << s.substr(0, 32) << " data type: " + << get_typename(data); + SWSS_LOG_ERROR("deserialize Failed: %s", _ss_ex.str().c_str()); + return -1; + } } @@ -126,9 +210,12 @@ template int map_to_zmsg(const Map& data, zmq_msg_t &msg) { - string s = serialize(data); + string s; + int rc = serialize(data, s); - int rc = zmq_msg_init_size(&msg, s.size()); + if (rc == 0) { + rc = zmq_msg_init_size(&msg, s.size()); + } if (rc == 0) { strncpy((char *)zmq_msg_data(&msg), s.c_str(), s.size()); } @@ -137,11 +224,11 @@ map_to_zmsg(const Map& data, zmq_msg_t &msg) template -void +int zmsg_to_map(zmq_msg_t &msg, Map& data) { string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); - deserialize(s, data); + return deserialize(s, data); } @@ -191,9 +278,10 @@ zmq_read_part(void *sock, int flag, int &more, DT data) if (rc != -1) { size_t more_size = sizeof (more); - zmsg_to_map(msg, data); + rc = zmsg_to_map(msg, data); - rc = zmq_getsockopt (sock, ZMQ_RCVMORE, &more, &more_size); + /* read more flag if message read fails to de-serialize */ + zmq_getsockopt (sock, ZMQ_RCVMORE, &more, &more_size); } zmq_msg_close(&msg); @@ -226,6 +314,7 @@ zmq_message_send(void *sock, P1 pt1, P2 pt2) { int rc = zmq_send_part(sock, pt2.empty() ? 0 : ZMQ_SNDMORE, pt1); + /* send second part, only if first is sent successfully */ if ((rc == 0) && (!pt2.empty())) { rc = zmq_send_part(sock, 0, pt2); } @@ -237,17 +326,20 @@ template int zmq_message_read(void *sock, int flag, P1 pt1, P2 pt2) { - int more = 0, rc; + int more = 0, rc, rc1; rc = zmq_read_part(sock, flag, more, pt1); - RET_ON_ERR(rc == 0, "Failed to read part1"); if (more) { - rc = zmq_read_part(sock, 0, more, pt2); - RET_ON_ERR(rc == 0, "Failed to read part1"); - RET_ON_ERR(!more, "Don't expect more than 2 parts"); + /* + * read second part if more is set, irrespective + * of any failure. More is set, only if sock is valid. + */ + rc1 = zmq_read_part(sock, 0, more, pt2); } - + RET_ON_ERR(rc == 0, "Failed to read part1"); + RET_ON_ERR(rc1 == 0, "Failed to read part2"); + RET_ON_ERR(!more, "Don't expect more than 2 parts"); out: return rc; } diff --git a/common/events_pi.h b/common/events_pi.h index fe248fed7..87b8ab6ae 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -63,14 +63,14 @@ class EventPublisher : public events_base int init(const string event_source); - void publish(event_handle_t &handle, const std::string &event_tag, + int publish(const std::string event_tag, const event_params_t *params); private: void *m_zmq_ctx; void *m_socket; - event_service m_event_svc; + event_service m_event_service; string m_event_source; @@ -104,7 +104,7 @@ class EventSubscriber : public events_base void *m_zmq_ctx; void *m_socket; - event_service m_event_svc; + event_service m_event_service; bool m_init; bool m_cache_read; @@ -121,7 +121,7 @@ class EventSubscriber : public events_base sequence_t seq; } evt_info_t; - typedef map track_info_t; + typedef map track_info_t; track_info_t m_track; events_data_lst_t m_from_cache; From d28399e6063910063af335c4e244a1d1ffe019a8 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Mon, 23 May 2022 22:11:53 +0000 Subject: [PATCH 10/97] compiled OK --- common/events.cpp | 9 ++++----- common/events_common.cpp | 3 ++- common/events_common.h | 10 ++++++++-- common/events_service.cpp | 21 +++++++++++++++++++++ 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 11fd2d18b..cf434234b 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -14,7 +14,7 @@ * All service interactions being async, a timeout is required * not to block forever on read. * - * The unit is in milliseconds (in sync with ZMQ_RCVTIMEO of + * The unit is in milliseconds in sync with ZMQ_RCVTIMEO of * zmq_setsockopt. */ @@ -115,7 +115,7 @@ EventPublisher::publish(const string tag, const event_params_t *params) rc = serialize(event_str_map, event_data[EVENT_STR_DATA]); RET_ON_ERR(rc == 0, "failed to serialize event str %s", - map_to_str(event_str_map)); + map_to_str(event_str_map).c_str()); } event_data[EVENT_RUNTIME_ID] = m_runtime_id; ++m_sequence; @@ -343,7 +343,7 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ else { if (m_track.size() > (MAX_PUBLISHERS_COUNT + 10)) { prune_track(); - m_track[event_data[EVENT_RUNTIME_ID] = evt_info_t(seq); + m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); } } if (missed_cnt >= 0) { @@ -378,8 +378,7 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ static EventSubscriber *s_subscriber = NULL; event_handle_t -events_init_subscriber(bool use_cache=false, - const event_subscribe_sources_t *sources=NULL) +events_init_subscriber(bool use_cache, const event_subscribe_sources_t *sources) { if (s_subscriber == NULL) { EventSubscriber *p = new EventSubscriber(); diff --git a/common/events_common.cpp b/common/events_common.cpp index f2083599d..8c704e968 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -11,7 +11,8 @@ map_str_str_t cfg_data = { CFG_VAL(XPUB_END_KEY, "tcp://127.0.0.1:5571"), CFG_VAL(REQ_REP_END_KEY, "tcp://127.0.0.1:5572"), CFG_VAL(CAPTURE_END_KEY, "tcp://127.0.0.1:5573"), - CFG_VAL(STATS_UPD_SECS, "5") + CFG_VAL(STATS_UPD_SECS, "5"), + CFG_VAL(CACHE_MAX_CNT, "") }; void diff --git a/common/events_common.h b/common/events_common.h index 49dc24eb7..8bb9d3ece 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -121,10 +121,16 @@ typedef map map_str_str_t; #define CFG_EVENTS_KEY "events" /* configurable entities' keys */ -#define XSUB_END_KEY "xsub_path" +/* zmq proxy's xsub & xpub end points */ +#define XSUB_END_KEY "xsub_path" #define XPUB_END_KEY "xpub_path" + +/* Eventd service end point; All service req/resp occur via this path */ #define REQ_REP_END_KEY "req_rep_path" + +/* Internal proxy to service path for capturing events for caching */ #define CAPTURE_END_KEY "capture_path" + #define STATS_UPD_SECS "stats_upd_secs" #define CACHE_MAX_CNT "cache_max_cnt" @@ -178,7 +184,7 @@ serialize(const Map& data, string &s) catch (exception& e) { stringstream _ser_ex_ss; - _ser_ex_ss << e.what() << "map data:" << map_to_str(data).substr(0, 32); + _ser_ex_ss << e.what() << "map type:" << get_typename(data); SWSS_LOG_ERROR("serialize Failed: %s", _ser_ex_ss.str().c_str()); return -1; } diff --git a/common/events_service.cpp b/common/events_service.cpp index 560432d79..46452c84e 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -1,5 +1,26 @@ #include "events_service.h" +/* + * For brainstorming, if helpful + * The cache messages are read in either direction + * Upon start, the caller gives a set of events read for about 2 seconds + * in non-blocking mode to give it as start stock. + * + * Upon cache stop, events collected MAX over a time is read by the caller. + * + * These messages are currently provided as vector list of strings. + * As cache start provided a small subset, it is given as part of start request + * Since cache read can be too many, multiple cache_Read requests are made + * until no more and each returns a subset as vector of strings. + * + * Another way, the entire cache in either direction can be sent/received + * via PAIR socket. But this woulkd need a special terminating message to + * indicate read end, as non-blocking read returning no event does not + * necessarily mean end + * + * Not sure, what the gain here is vs current approach of vector + * Just a note for now, not to lose a line of possibility. + */ int event_service::init_client(void *zmq_ctx, int block_ms) From f2694ea7840371a0ce45b771050a3083a984aba0 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 24 May 2022 15:45:07 +0000 Subject: [PATCH 11/97] common ut passes --- common/Makefile.am | 2 +- common/events_common.cpp | 1 + common/events_common.h | 35 ++++++++++++++++++------------- common/events_pi.h | 1 - tests/Makefile.am | 5 +++-- tests/events_common_ut.cpp | 42 +++++++++++++++++++++++++++++++++++--- 6 files changed, 65 insertions(+), 21 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index f399839c8..e54a8f785 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -72,7 +72,7 @@ libswsscommon_la_SOURCES = \ libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS) -libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization +libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid -lboost_serialization swssloglevel_SOURCES = loglevel.cpp diff --git a/common/events_common.cpp b/common/events_common.cpp index 8c704e968..87f748320 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -1,6 +1,7 @@ #include "events_common.h" int zerrno = 0; +int running_ut = 0; /* * defaults for all config entries diff --git a/common/events_common.h b/common/events_common.h index 8bb9d3ece..0113086be 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include "string.h" @@ -35,6 +34,8 @@ extern int zerrno; */ #define MAX_PUBLISHERS_COUNT 1000 +extern int running_ut; + /* TODO: Combine two SWSS_LOG_ERROR into one */ #define RET_ON_ERR(res, msg, ...)\ @@ -43,6 +44,9 @@ extern int zerrno; zerrno = zmq_errno(); \ SWSS_LOG_ERROR(msg, ##__VA_ARGS__); \ SWSS_LOG_ERROR("last:errno=%d zerr=%d", _e, zerrno); \ + if (running_ut) { \ + printf(msg, ##__VA_ARGS__); \ + printf("last:errno=%d zerr=%d\n", _e, zerrno); }\ goto out; } #define ERR_CHECK(res, ...) {\ @@ -243,9 +247,10 @@ zmsg_to_map(zmq_msg_t &msg, Map& data) * First part only has the event source, so receivers could * filter by source. * - * Second part contains map as defined in internal_event_t. - * The map is serialized and sent as string. - * + * Second part contains serialized form of map as defined in internal_event_t. + * The map is serialized and sent as string events_data_type_t. + * Caching that handles of set of events, handleas ordered events + * as declared in events_data_lst_t. */ /* * This is data going over wire and using cache. So be conservative @@ -261,10 +266,12 @@ typedef map internal_event_t; typedef uint32_t sequence_t; typedef string runtime_id_t; -internal_event_t internal_event_ref = { - { EVENT_STR_DATA, "" }, - { EVENT_RUNTIME_ID, "" }, - { EVENT_SEQUENCE, "" } }; +/* + * internal_event_t internal_event_ref = { + * { EVENT_STR_DATA, "" }, + * { EVENT_RUNTIME_ID, "" }, + * { EVENT_SEQUENCE, "" } }; + */ /* ZMQ message part 2 contains serialized version of internal_event_t */ typedef string events_data_type_t; @@ -273,7 +280,7 @@ typedef vector events_data_lst_t; template int -zmq_read_part(void *sock, int flag, int &more, DT data) +zmq_read_part(void *sock, int flag, int &more, DT &data) { zmq_msg_t msg; @@ -298,15 +305,15 @@ zmq_read_part(void *sock, int flag, int &more, DT data) template int -zmq_send_part(void *sock, int flag, DT data) +zmq_send_part(void *sock, int flag, DT &data) { zmq_msg_t msg; int rc = map_to_zmsg(data, msg); - RET_ON_ERR(rc == 0, "Failed to map to zmsg %d", 5); + RET_ON_ERR(rc == 0, "Failed to map to zmsg %d", rc); rc = zmq_msg_send (&msg, sock, flag); - RET_ON_ERR(rc != -1, "Failed to send part %d", 5); + RET_ON_ERR(rc != -1, "Failed to send part %d", rc); rc = 0; out: @@ -316,7 +323,7 @@ zmq_send_part(void *sock, int flag, DT data) template int -zmq_message_send(void *sock, P1 pt1, P2 pt2) +zmq_message_send(void *sock, P1 &pt1, P2 &pt2) { int rc = zmq_send_part(sock, pt2.empty() ? 0 : ZMQ_SNDMORE, pt1); @@ -330,7 +337,7 @@ zmq_message_send(void *sock, P1 pt1, P2 pt2) template int -zmq_message_read(void *sock, int flag, P1 pt1, P2 pt2) +zmq_message_read(void *sock, int flag, P1 &pt1, P2 &pt2) { int more = 0, rc, rc1; diff --git a/common/events_pi.h b/common/events_pi.h index 87b8ab6ae..b30a87ff6 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -7,7 +7,6 @@ #include #include #include -#include #include #include "string.h" #include "json.hpp" diff --git a/tests/Makefile.am b/tests/Makefile.am index 8d8161e40..1fe2d8c79 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -36,8 +36,9 @@ tests_SOURCES = redis_ut.cpp \ status_code_util_test.cpp \ saiaclschema_ut.cpp \ main.cpp \ - events_common_ut.cpp + events_common_ut.cpp \ + events_service_ut.cpp tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) -tests_LDADD = $(LDADD_GTEST) -lpthread -L$(top_srcdir)/common -lswsscommon $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) +tests_LDADD = $(LDADD_GTEST) -lpthread -L$(top_srcdir)/common -lswsscommon $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -luuid -lboost_serialization diff --git a/tests/events_common_ut.cpp b/tests/events_common_ut.cpp index db067df16..67f962a63 100644 --- a/tests/events_common_ut.cpp +++ b/tests/events_common_ut.cpp @@ -12,7 +12,7 @@ using namespace std; const char *test_cfg_data = "{\ \"events\" : { \ \"xsub_path\": \"xsub_path\", \ - \"pair_path\": \"pair_path\" \ + \"req_rep_path\": \"req_rep_path\" \ }\ }"; @@ -20,7 +20,7 @@ const char *test_cfg_data = "{\ TEST(events_common, get_config) { EXPECT_EQ(string("tcp://127.0.0.1:5570"), get_config(string(XSUB_END_KEY))); - EXPECT_EQ(string("tcp://127.0.0.1:5573"), get_config(string(PAIR_END_KEY))); + EXPECT_EQ(string("tcp://127.0.0.1:5572"), get_config(string(REQ_REP_END_KEY))); EXPECT_EQ(string("5"), get_config(string(STATS_UPD_SECS))); ofstream tfile; @@ -32,9 +32,11 @@ TEST(events_common, get_config) read_init_config(tfile_name); EXPECT_EQ(string(XSUB_END_KEY), get_config(string(XSUB_END_KEY))); - EXPECT_EQ(string(PAIR_END_KEY), get_config(string(PAIR_END_KEY))); + EXPECT_EQ(string(REQ_REP_END_KEY), get_config(string(REQ_REP_END_KEY))); EXPECT_EQ(string("5"), get_config(string(STATS_UPD_SECS))); + EXPECT_EQ(100, get_config_data(CACHE_MAX_CNT, 100)); + cout << "events_common: get_config succeeded\n"; } @@ -68,3 +70,37 @@ TEST(events_common, msg) EXPECT_EQ(t, t1); } +TEST(events_common, send_recv) +{ + running_ut = 1; + + char *path = "tcp://127.0.0.1:5570"; + void *zmq_ctx = zmq_ctx_new(); + void *sock_p0 = zmq_socket (zmq_ctx, ZMQ_PAIR); + EXPECT_EQ(0, zmq_connect (sock_p0, path)); + + void *sock_p1 = zmq_socket (zmq_ctx, ZMQ_PAIR); + EXPECT_EQ(0, zmq_bind (sock_p1, path)); + + string source("Hello"), source1; + + map m = {{"foo", "bar"}, {"hello", "world"}, {"good", "day"}}; + map m1; + + EXPECT_EQ(0, zmq_message_send(sock_p0, source, m)); + + EXPECT_EQ(0, zmq_message_read(sock_p1, 0, source1, m1)); + + EXPECT_EQ(source, source1); + EXPECT_EQ(m, m1); + zmq_close(sock_p0); + zmq_close(sock_p1); + zmq_ctx_term(zmq_ctx); +} + + + + + + + From 4c8373d5223802259353968cf60e60420588960d Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 24 May 2022 18:03:02 +0000 Subject: [PATCH 12/97] events_service unit tests complete --- common/events_common.h | 4 ++-- common/events_service.cpp | 34 ++++++++++++++++++++++------------ common/events_service.h | 7 ++++--- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/common/events_common.h b/common/events_common.h index 0113086be..11083acf4 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -305,7 +305,7 @@ zmq_read_part(void *sock, int flag, int &more, DT &data) template int -zmq_send_part(void *sock, int flag, DT &data) +zmq_send_part(void *sock, int flag, const DT &data) { zmq_msg_t msg; @@ -323,7 +323,7 @@ zmq_send_part(void *sock, int flag, DT &data) template int -zmq_message_send(void *sock, P1 &pt1, P2 &pt2) +zmq_message_send(void *sock, const P1 &pt1, const P2 &pt2) { int rc = zmq_send_part(sock, pt2.empty() ? 0 : ZMQ_SNDMORE, pt1); diff --git a/common/events_service.cpp b/common/events_service.cpp index 46452c84e..0ff8a114b 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -36,7 +36,7 @@ event_service::init_client(void *zmq_ctx, int block_ms) // Set read timeout. // rc = zmq_setsockopt (sock, ZMQ_RCVTIMEO, &block_ms, sizeof (block_ms)); - RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY).c_str()); + RET_ON_ERR(rc == 0, "Failed to ZMQ_RCVTIMEO to %d", block_ms); m_socket = sock; out: @@ -44,7 +44,7 @@ event_service::init_client(void *zmq_ctx, int block_ms) } int -event_service::init_server(void *zmq_ctx) +event_service::init_server(void *zmq_ctx, int block_ms) { int rc = -1; @@ -54,6 +54,11 @@ event_service::init_server(void *zmq_ctx) rc = zmq_bind (sock, get_config(REQ_REP_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Failed to bind to %s", get_config(REQ_REP_END_KEY).c_str()); + // Set read timeout. + // + rc = zmq_setsockopt (sock, ZMQ_RCVTIMEO, &block_ms, sizeof (block_ms)); + RET_ON_ERR(rc == 0, "Failed to ZMQ_RCVTIMEO to %d", block_ms); + m_socket = sock; out: return rc; @@ -102,11 +107,11 @@ event_service::cache_init() int -event_service::cache_start(events_data_lst_t &lst) +event_service::cache_start(const events_data_lst_t &lst) { int rc; - RET_ON_ERR((rc = send_recv(EVENT_CACHE_START, &lst) == 0), + RET_ON_ERR((rc = send_recv(EVENT_CACHE_START, &lst)) == 0, "Failed to send cache start"); out: return rc; @@ -118,7 +123,7 @@ event_service::cache_stop() { int rc; - RET_ON_ERR((rc = send_recv(EVENT_CACHE_STOP) == 0), + RET_ON_ERR((rc = send_recv(EVENT_CACHE_STOP)) == 0, "Failed to send cache stop"); out: return rc; @@ -130,7 +135,7 @@ event_service::cache_read(events_data_lst_t &lst) { int rc; - RET_ON_ERR((rc = send_recv(EVENT_CACHE_READ, &lst) == 0), + RET_ON_ERR((rc = send_recv(EVENT_CACHE_READ, NULL, &lst)) == 0, "Failed to send cache read"); out: return rc; @@ -140,6 +145,7 @@ event_service::cache_read(events_data_lst_t &lst) int event_service::channel_read(int &code, events_data_lst_t &data) { + events_data_lst_t().swap(data); return zmq_message_read(m_socket, 0, code, data); } @@ -152,19 +158,23 @@ event_service::channel_write(int code, const events_data_lst_t &data) int -event_service::send_recv(int code, events_data_lst_t *p) +event_service::send_recv(int code, const events_data_lst_t *lst_in, + events_data_lst_t *lst_out) { events_data_lst_t l; int resp; - if(p == NULL) { - p = &l; + if(lst_in == NULL) { + lst_in = &l; } - int rc = channel_write(code, *p); + int rc = channel_write(code, *lst_in); RET_ON_ERR(rc == 0, "failing to send code=%d", code); - rc = channel_read(resp, *p); + if (lst_out == NULL) { + lst_out = &l; + } + rc = channel_read(resp, *lst_out); RET_ON_ERR(rc == 0, "failing to read resp for code=%d", code); rc = resp; @@ -178,6 +188,6 @@ event_service::send_recv(int code, events_data_lst_t *p) void event_service::close_service() { - if (m_socket == NULL) { zmq_close(m_socket); m_socket = NULL; } + if (m_socket != NULL) { zmq_close(m_socket); m_socket = NULL; } } diff --git a/common/events_service.h b/common/events_service.h index b88c9ad09..d7d9f6848 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -80,7 +80,7 @@ class event_service { */ int init_client(void *zmq_ctx, int block_ms = -1); - int init_server(void *zmq_ctx); + int init_server(void *zmq_ctx, int block_ms = -1); /* * Event cache service is singleton service @@ -128,7 +128,7 @@ class event_service { * 1 - Already running * -1 - On failure. */ - int cache_start(events_data_lst_t &lst); + int cache_start(const events_data_lst_t &lst); /* * Called to stop caching events @@ -259,7 +259,8 @@ class event_service { * return: * Any failure or response code from server. */ - int send_recv(int code, events_data_lst_t *lst = NULL); + int send_recv(int code, const events_data_lst_t *lst_in = NULL, + events_data_lst_t *lst_out = NULL); /* * de-init/close service From 2197e85c73d089172f2a1307163b5b4e53f55acd Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Wed, 25 May 2022 00:02:16 +0000 Subject: [PATCH 13/97] test code in progress --- common/events.cpp | 1 + common/events.h | 2 +- tests/Makefile.am | 3 +- tests/events_service_ut.cpp | 116 ++++++++++++++++++++++++++++++++ tests/events_ut.cpp | 128 ++++++++++++++++++++++++++++++++++++ 5 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 tests/events_service_ut.cpp create mode 100644 tests/events_ut.cpp diff --git a/common/events.cpp b/common/events.cpp index cf434234b..c4be653ef 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -71,6 +71,7 @@ int EventPublisher::init(const string event_source) EventPublisher::~EventPublisher() { + m_event_service.close_service(); zmq_close(m_socket); zmq_ctx_term(m_zmq_ctx); } diff --git a/common/events.h b/common/events.h index 8e3732e86..d9e7e64cb 100644 --- a/common/events.h +++ b/common/events.h @@ -38,7 +38,7 @@ typedef void* event_handle_t; * NULL on failure */ -event_handle_t events_init_publisher(std::string event_source); +event_handle_t events_init_publisher(const std::string event_source); /* * De-init/free the publisher diff --git a/tests/Makefile.am b/tests/Makefile.am index 1fe2d8c79..ec55a964f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -37,7 +37,8 @@ tests_SOURCES = redis_ut.cpp \ saiaclschema_ut.cpp \ main.cpp \ events_common_ut.cpp \ - events_service_ut.cpp + events_service_ut.cpp \ + events_ut.cpp tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) diff --git a/tests/events_service_ut.cpp b/tests/events_service_ut.cpp new file mode 100644 index 000000000..0bf01b649 --- /dev/null +++ b/tests/events_service_ut.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "common/events_common.h" +#include "common/events_service.h" + +using namespace std; + +static bool do_terminate = false; +static void *zmq_ctx = NULL; +static event_service service_cl, service_svr; +static int server_rd_code, server_ret; +static events_data_lst_t server_rd_lst, server_wr_lst; + +void serve_commands() +{ + int code; + events_data_lst_t lst; + EXPECT_EQ(0, service_svr.init_server(zmq_ctx, 1000)); + while(!do_terminate) { + if (0 != service_svr.channel_read(code, lst)) { + /* check client service status, before blocking on read */ + continue; + } + server_rd_code = code; + server_rd_lst = lst; + + printf("serve_commands code=%dlst=%d, %d\n", server_rd_code, (int)server_rd_lst.size(), (int)lst.size()); + switch(code) { + case EVENT_CACHE_INIT: + server_ret = 0; + server_wr_lst.clear(); + break; + case EVENT_CACHE_START: + server_ret = 0; + server_wr_lst.clear(); + break; + case EVENT_CACHE_STOP: + server_ret = 0; + server_wr_lst.clear(); + break; + case EVENT_CACHE_READ: + server_ret = 0; + server_wr_lst = { "rerer", "rrrr", "cccc" }; + break; + case EVENT_ECHO: + server_ret = 0; + server_wr_lst = lst; + break; + default: + EXPECT_TRUE(false); + server_ret = -1; + break; + } + EXPECT_EQ(0, service_svr.channel_write(server_ret, server_wr_lst)); + } + service_svr.close_service(); + EXPECT_FALSE(service_svr.is_active()); +} + + +TEST(events_common, cache_cmds) +{ + events_data_lst_t lst_start, lst; + running_ut = 1; + + zmq_ctx = zmq_ctx_new(); + EXPECT_TRUE(NULL != zmq_ctx); + + thread thr(&serve_commands); + + EXPECT_EQ(0, service_cl.init_client(zmq_ctx)); + + EXPECT_EQ(0, service_cl.cache_init()); + /* Cache init sends echo upon success */ + EXPECT_EQ(EVENT_ECHO, server_rd_code); + EXPECT_TRUE(server_rd_lst.empty()); + EXPECT_EQ(server_rd_lst, server_wr_lst); + + /* + * Bunch of serialized internal_event_t as strings + * Sending random for test purpose + */ + lst_start = events_data_lst_t( + { "hello", "world", "ok" }); + EXPECT_EQ(0, service_cl.cache_start(lst_start)); + EXPECT_EQ(EVENT_CACHE_START, server_rd_code); + EXPECT_EQ(lst_start, server_rd_lst); + + EXPECT_EQ(0, service_cl.cache_stop()); + EXPECT_EQ(EVENT_CACHE_STOP, server_rd_code); + EXPECT_TRUE(server_rd_lst.empty()); + + EXPECT_EQ(0, service_cl.cache_read(lst)); + EXPECT_EQ(EVENT_CACHE_READ, server_rd_code); + EXPECT_TRUE(server_rd_lst.empty()); + EXPECT_EQ(server_wr_lst, lst); + + string s("hello"), s1; + EXPECT_EQ(0, service_cl.echo_send(s)); + EXPECT_EQ(0, service_cl.echo_receive(s1)); + EXPECT_EQ(EVENT_ECHO, server_rd_code); + EXPECT_FALSE(server_rd_lst.empty()); + EXPECT_EQ(s1, s); + + do_terminate = true; + service_cl.close_service(); + EXPECT_FALSE(service_cl.is_active()); + thr.join(); + zmq_ctx_term(zmq_ctx); +} + diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp new file mode 100644 index 000000000..cff160e60 --- /dev/null +++ b/tests/events_ut.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "common/events_common.h" +#include "common/events.h" +#include "common/events_pi.h" + +using namespace std; + +static bool terminate_thr = false; +static void *zmq_ctx = NULL; + +void pub_serve_commands() +{ + event_service service_svr; + + EXPECT_EQ(0, service_svr.init_server(zmq_ctx, 1000)); + + while(!terminate_thr) { + int code, resp; + events_data_lst_t lst; + + printf("reading ...\n"); + if (0 != service_svr.channel_read(code, lst)) { + /* check client service status, before blocking on read */ + continue; + } + printf("pub serve_commands code=%d lst=%d\n", code, (int)lst.size()); + switch(code) { + case EVENT_CACHE_INIT: + resp = 0; + lst.clear(); + break; + case EVENT_CACHE_START: + resp = 0; + lst.clear(); + break; + case EVENT_CACHE_STOP: + resp = 0; + lst.clear(); + break; + case EVENT_CACHE_READ: + resp = 0; + lst = { "rerer", "rrrr", "cccc" }; + break; + case EVENT_ECHO: + resp = 0; + break; + default: + EXPECT_TRUE(false); + resp = -1; + break; + } + EXPECT_EQ(0, service_svr.channel_write(resp, lst)); + } + service_svr.close_service(); + EXPECT_FALSE(service_svr.is_active()); + printf("exiting thread\n"); +} + + +void run_sub() +{ + void *mock_sub = zmq_socket (zmq_ctx, ZMQ_SUB); + string source_read; + internal_event_t ev_int; + + EXPECT_TRUE(NULL != mock_sub); + EXPECT_EQ(0, zmq_bind(mock_sub, get_config(XSUB_END_KEY).c_str())); + EXPECT_EQ(0, zmq_setsockopt(mock_sub, ZMQ_SUBSCRIBE, "", 0)); + + printf("waiting to read\n"); + EXPECT_EQ(0, zmq_message_read(mock_sub, 0, source_read, ev_int)); + printf("done reading\n"); + zmq_close(mock_sub); +} + +TEST(events, publish) +{ + string evt_source("sonic-events-bgp"); + string evt_tag("bgp-state"); + event_params_t params1({{"ip", "10.10.10.10"}, {"state", "up"}}); + event_params_t params_read; + string evt_key = evt_source + ":" + evt_tag; + map_str_str_t read_evt; + + running_ut = 1; + + zmq_ctx = zmq_ctx_new(); + EXPECT_TRUE(NULL != zmq_ctx); + + thread thr(&pub_serve_commands); + thread thr_sub(&run_sub); + + printf("Calling events_init_publisher path=%s\n", get_config(XSUB_END_KEY).c_str()); + event_handle_t h = events_init_publisher(evt_source); + EXPECT_TRUE(NULL != h); + printf("DONE events_init_publisher\n"); + + /* Take a pause to allow publish to connect async */ + this_thread::sleep_for(chrono::milliseconds(1000)); + + printf("called publish\n"); + EXPECT_EQ(0, event_publish(h, evt_tag, ¶ms1)); + printf("done publish\n"); + + /* Don't need event's service anymore */ + terminate_thr = true; + + // EXPECT_EQ(evt_source, source_read); + + thr.join(); + thr_sub.join(); + printf("Joined thread\n"); + + events_deinit_publisher(h); + + printf("deinit done; terminating ctx\n"); + zmq_ctx_term(zmq_ctx); + printf("ctx terminated\n"); + +} + From 67fbe19be6cd0c722bb5fec15ac856cf0e0ea82e Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 26 May 2022 00:23:33 +0000 Subject: [PATCH 14/97] evens publish covere by unit test --- tests/events_common_ut.cpp | 12 ++- tests/events_ut.cpp | 181 +++++++++++++++++++++++++++++++------ 2 files changed, 163 insertions(+), 30 deletions(-) diff --git a/tests/events_common_ut.cpp b/tests/events_common_ut.cpp index 67f962a63..03a5ecf91 100644 --- a/tests/events_common_ut.cpp +++ b/tests/events_common_ut.cpp @@ -40,14 +40,20 @@ TEST(events_common, get_config) cout << "events_common: get_config succeeded\n"; } +void +events_validate_ts(const string s) +{ + string reg = "^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\.[0-9]{1,6}Z$"; + + EXPECT_TRUE(regex_match (s, regex(reg))); +} + TEST(events_common, ts) { string s = get_timestamp(); - string reg = "^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\.[0-9]{1,6}Z$"; - cout << s << "\n"; - EXPECT_TRUE(regex_match (s, regex(reg))); + events_validate_ts(s); } TEST(events_common, msg) diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index cff160e60..859c56273 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -12,25 +12,26 @@ using namespace std; -static bool terminate_thr = false; +static bool terminate_svc = false; +static bool terminate_sub = false; static void *zmq_ctx = NULL; +void events_validate_ts(const string s); + void pub_serve_commands() { event_service service_svr; EXPECT_EQ(0, service_svr.init_server(zmq_ctx, 1000)); - while(!terminate_thr) { + while(!terminate_svc) { int code, resp; events_data_lst_t lst; - printf("reading ...\n"); if (0 != service_svr.channel_read(code, lst)) { /* check client service status, before blocking on read */ continue; } - printf("pub serve_commands code=%d lst=%d\n", code, (int)lst.size()); switch(code) { case EVENT_CACHE_INIT: resp = 0; @@ -60,69 +61,195 @@ void pub_serve_commands() } service_svr.close_service(); EXPECT_FALSE(service_svr.is_active()); - printf("exiting thread\n"); } +string read_source; +internal_event_t read_evt; + void run_sub() { void *mock_sub = zmq_socket (zmq_ctx, ZMQ_SUB); - string source_read; + string source; internal_event_t ev_int; + int block_ms = 200; EXPECT_TRUE(NULL != mock_sub); EXPECT_EQ(0, zmq_bind(mock_sub, get_config(XSUB_END_KEY).c_str())); EXPECT_EQ(0, zmq_setsockopt(mock_sub, ZMQ_SUBSCRIBE, "", 0)); + EXPECT_EQ(0, zmq_setsockopt(mock_sub, ZMQ_RCVTIMEO, &block_ms, sizeof (block_ms, 0))); + + while(!terminate_sub) { + if (0 == zmq_message_read(mock_sub, 0, source, ev_int)) { + read_evt.swap(ev_int); + read_source.swap(source); + } + } - printf("waiting to read\n"); - EXPECT_EQ(0, zmq_message_read(mock_sub, 0, source_read, ev_int)); - printf("done reading\n"); zmq_close(mock_sub); } -TEST(events, publish) +string +parse_read_evt(string &source, internal_event_t &evt, + string &rid, sequence_t &seq, string &key, event_params_t ¶ms) { - string evt_source("sonic-events-bgp"); - string evt_tag("bgp-state"); - event_params_t params1({{"ip", "10.10.10.10"}, {"state", "up"}}); - event_params_t params_read; - string evt_key = evt_source + ":" + evt_tag; - map_str_str_t read_evt; + int i; + string ret; + + rid.clear(); + seq = 0; + key.clear(); + event_params_t().swap(params); + + /* Pause with timeout for reading published message */ + for(i=0; source.empty() && (i < 20); ++i) { + this_thread::sleep_for(chrono::milliseconds(10)); + } + + EXPECT_FALSE(source.empty()); + EXPECT_EQ(3, evt.size()); + + for (const auto e: evt) { + if (e.first == EVENT_STR_DATA) { + map_str_str_t m; + EXPECT_EQ(0, deserialize(e.second, m)); + EXPECT_EQ(1, m.size()); + key = m.begin()->first; + EXPECT_EQ(0, deserialize(m.begin()->second, params)); + cout << "EVENT_STR_DATA: " << e.second << "\n"; + } + else if (e.first == EVENT_RUNTIME_ID) { + rid = e.second; + cout << "EVENT_RUNTIME_ID: " << e.second << "\n"; + } + else if (e.first == EVENT_SEQUENCE) { + stringstream ss(e.second); + ss >> seq; + cout << "EVENT_SEQUENCE: " << seq << "\n"; + } + else { + EXPECT_FALSE(true); + } + } + + EXPECT_FALSE(rid.empty()); + EXPECT_FALSE(seq == 0); + EXPECT_FALSE(key.empty()); + EXPECT_FALSE(params.empty()); + + /* clear it before call to next read */ + ret.swap(source); + internal_event_t().swap(evt); + + return ret; +} + + +TEST(events, publish) +{ running_ut = 1; + string evt_source0("sonic-events-bgp"); + string evt_source1("sonic-events-xyz"); + string evt_tag0("bgp-state"); + string evt_tag1("xyz-state"); + event_params_t params0({{"ip", "10.10.10.10"}, {"state", "up"}}); + event_params_t params1; + event_params_t::iterator it_param; + + string rid0, rid1; + sequence_t seq0, seq1 = 0; + string rd_key0, rd_key1; + event_params_t rd_params0, rd_params1; + zmq_ctx = zmq_ctx_new(); EXPECT_TRUE(NULL != zmq_ctx); thread thr(&pub_serve_commands); thread thr_sub(&run_sub); - printf("Calling events_init_publisher path=%s\n", get_config(XSUB_END_KEY).c_str()); - event_handle_t h = events_init_publisher(evt_source); + event_handle_t h = events_init_publisher(evt_source0); EXPECT_TRUE(NULL != h); - printf("DONE events_init_publisher\n"); /* Take a pause to allow publish to connect async */ - this_thread::sleep_for(chrono::milliseconds(1000)); + this_thread::sleep_for(chrono::milliseconds(300)); + + EXPECT_EQ(0, event_publish(h, evt_tag0, ¶ms0)); + + parse_read_evt(read_source, read_evt, rid0, seq0, rd_key0, rd_params0); + + EXPECT_EQ(seq0, 1); + EXPECT_EQ(rd_key0, evt_source0 + ":" + evt_tag0); + + it_param = rd_params0.find(event_ts_param); + EXPECT_TRUE(it_param != rd_params0.end()); + if (it_param != rd_params0.end()) { + events_validate_ts(it_param->second); + rd_params0.erase(it_param); + } + + EXPECT_EQ(rd_params0, params0); + + // Publish second message + // + EXPECT_EQ(0, event_publish(h, evt_tag1, ¶ms1)); + + parse_read_evt(read_source, read_evt, rid1, seq1, rd_key1, rd_params1); + + EXPECT_EQ(rid0, rid1); + EXPECT_EQ(seq1, 2); + EXPECT_EQ(rd_key1, evt_source0 + ":" + evt_tag1); + + it_param = rd_params1.find(event_ts_param); + EXPECT_TRUE(it_param != rd_params1.end()); + if (it_param != rd_params1.end()) { + events_validate_ts(it_param->second); + rd_params1.erase(it_param); + } + + EXPECT_EQ(rd_params1, params1); + + + // Publish using a new source + // + event_handle_t h1 = events_init_publisher(evt_source1); + EXPECT_TRUE(NULL != h1); + + /* Take a pause to allow publish to connect async */ + this_thread::sleep_for(chrono::milliseconds(300)); + + EXPECT_EQ(0, event_publish(h1, evt_tag0, ¶ms0)); + + parse_read_evt(read_source, read_evt, rid0, seq0, rd_key0, rd_params0); + + EXPECT_NE(rid0, rid1); + EXPECT_EQ(seq0, 1); + EXPECT_EQ(rd_key0, evt_source1 + ":" + evt_tag0); + + it_param = rd_params0.find(event_ts_param); + EXPECT_TRUE(it_param != rd_params0.end()); + if (it_param != rd_params0.end()) { + events_validate_ts(it_param->second); + rd_params0.erase(it_param); + } + + EXPECT_EQ(rd_params0, params0); - printf("called publish\n"); - EXPECT_EQ(0, event_publish(h, evt_tag, ¶ms1)); - printf("done publish\n"); /* Don't need event's service anymore */ - terminate_thr = true; + terminate_svc = true; + terminate_sub = true; // EXPECT_EQ(evt_source, source_read); thr.join(); thr_sub.join(); - printf("Joined thread\n"); events_deinit_publisher(h); + events_deinit_publisher(h1); - printf("deinit done; terminating ctx\n"); zmq_ctx_term(zmq_ctx); - printf("ctx terminated\n"); } From 9d646344fa8c547c4aab3377549fb6ff0b9437f2 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 27 May 2022 20:26:48 +0000 Subject: [PATCH 15/97] events 75% covered by UT --- common/events.cpp | 33 +++-- common/events.h | 20 ++- common/events_common.cpp | 1 + common/events_common.h | 2 + common/events_pi.h | 1 + tests/events_ut.cpp | 260 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 302 insertions(+), 15 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index c4be653ef..e0cff70f9 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -16,9 +16,17 @@ * * The unit is in milliseconds in sync with ZMQ_RCVTIMEO of * zmq_setsockopt. + * + * Publisher uses more to shadow async connectivity from PUB to + * XSUB end point of eventd's proxy. Hene have a less value. + * + * Subscriber uses it for cache management and here we need a + * longer timeout, to handle slow proxy. This timeout value's only + * impact could be subscriber process trying to terminate. */ -#define EVENTS_SERVICE_TIMEOUT_MILLISECS 200 +#define EVENTS_SERVICE_TIMEOUT_MS_PUB 200 +#define EVENTS_SERVICE_TIMEOUT_MS_SUB 2000 /* * Track created publishers to avoid duplicates @@ -50,7 +58,7 @@ int EventPublisher::init(const string event_source) * Event service could be down. So have a timeout. * */ - rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MILLISECS); + rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MS_PUB); RET_ON_ERR (rc == 0, "Failed to init event service"); rc = m_event_service.echo_send("hello"); @@ -87,7 +95,7 @@ EventPublisher::publish(const string tag, const event_params_t *params) string s; /* Failure is no-op; The eventd service my be down - * NOTE: This call atmost blocks for EVENTS_SERVICE_TIMEOUT_MILLISECS + * NOTE: This call atmost blocks for EVENTS_SERVICE_TIMEOUT_MS_PUB * as provided in publisher init. */ m_event_service.echo_receive(s); @@ -240,7 +248,8 @@ EventSubscriber::~EventSubscriber() int -EventSubscriber::init(bool use_cache, const event_subscribe_sources_t *subs_sources) +EventSubscriber::init(bool use_cache, int recv_timeout, + const event_subscribe_sources_t *subs_sources) { /* * Initiate SUBS connection to XPUB end point. @@ -268,8 +277,13 @@ EventSubscriber::init(bool use_cache, const event_subscribe_sources_t *subs_sour } } + if (recv_timeout != -1) { + rc = zmq_setsockopt (m_socket, ZMQ_RCVTIMEO, &recv_timeout, sizeof (recv_timeout)); + RET_ON_ERR(rc == 0, "Failed to ZMQ_RCVTIMEO to %d", recv_timeout); + } + if (use_cache) { - rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MILLISECS); + rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MS_SUB); RET_ON_ERR(rc == 0, "Fails to init the service"); if (m_event_service.cache_stop() == 0) { @@ -379,12 +393,13 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ static EventSubscriber *s_subscriber = NULL; event_handle_t -events_init_subscriber(bool use_cache, const event_subscribe_sources_t *sources) +events_init_subscriber(bool use_cache, int recv_timeout, + const event_subscribe_sources_t *sources) { if (s_subscriber == NULL) { EventSubscriber *p = new EventSubscriber(); - RET_ON_ERR(p->init(use_cache, sources) == 0, + RET_ON_ERR(p->init(use_cache, recv_timeout, sources) == 0, "Failed to init subscriber"); s_subscriber = p; @@ -416,4 +431,8 @@ event_receive(event_handle_t handle, string &key, return -1; } +int event_last_error() +{ + return recv_last_err; +} diff --git a/common/events.h b/common/events.h index d9e7e64cb..7360089ba 100644 --- a/common/events.h +++ b/common/events.h @@ -113,6 +113,13 @@ typedef std::vector event_subscribe_sources_t; * The cache service caches events during session down time. The deinit * start the caching and init call stops the caching. * + * recv_timeout + * Read blocks by default until an event is available for read. + * 0 - Returns immediately, with or w/o event + * -1 - Default; Blocks until an event is available for read + * N - Count ofd milliseconds to wait for an event. + * + * * lst_subscribe_sources_t * List of subscription sources of interest. * The source value is the corresponding YANG module name. @@ -123,6 +130,7 @@ typedef std::vector event_subscribe_sources_t; * NULL on failure */ event_handle_t events_init_subscriber(bool use_cache=false, + int recv_timeout = -1, const event_subscribe_sources_t *sources=NULL); /* @@ -174,13 +182,23 @@ void events_deinit_subscriber(event_handle_t &handle); * * return: * 0 - On success - * -1 - On failure. The handle is not valid. + * -1 - On failure. The handle is not valid or upon receive timeout. * */ int event_receive(event_handle_t handle, std::string &key, event_params_t ¶ms, int &missed_cnt); +/* + * Get error code for last receive + * + * Set to EAGAIN on timeout + * Any other value implies fatal error. + * + */ +int event_last_error(); + + /* * Cache drain timeout. * diff --git a/common/events_common.cpp b/common/events_common.cpp index 87f748320..6a77fdcb1 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -1,6 +1,7 @@ #include "events_common.h" int zerrno = 0; +int recv_last_err = 0; int running_ut = 0; /* diff --git a/common/events_common.h b/common/events_common.h index 11083acf4..b0907be28 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -25,6 +25,7 @@ using namespace chrono; extern int errno; extern int zerrno; +extern int recv_last_err; /* * Max count of possible concurrent event publishers @@ -287,6 +288,7 @@ zmq_read_part(void *sock, int flag, int &more, DT &data) more = 0; zmq_msg_init(&msg); int rc = zmq_msg_recv(&msg, sock, flag); + recv_last_err = zerrno; if (rc != -1) { size_t more_size = sizeof (more); diff --git a/common/events_pi.h b/common/events_pi.h index b30a87ff6..2079eb968 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -93,6 +93,7 @@ class EventSubscriber : public events_base EventSubscriber(); int init(bool use_cache=false, + int recv_timeout= -1, const event_subscribe_sources_t *subs_sources=NULL); virtual ~EventSubscriber(); diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 859c56273..30809d72a 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -12,18 +12,24 @@ using namespace std; -static bool terminate_svc = false; -static bool terminate_sub = false; static void *zmq_ctx = NULL; +int last_svc_code = -1; + void events_validate_ts(const string s); +events_data_lst_t lst_cache, lst_read; + +#define ARRAY_SIZE(d) (sizeof(d) / sizeof((d)[0])) + +static bool terminate_svc = false; + void pub_serve_commands() { event_service service_svr; + EXPECT_TRUE(NULL != zmq_ctx); EXPECT_EQ(0, service_svr.init_server(zmq_ctx, 1000)); - while(!terminate_svc) { int code, resp; events_data_lst_t lst; @@ -32,6 +38,8 @@ void pub_serve_commands() /* check client service status, before blocking on read */ continue; } + printf("Read code=%d lst=%d\n", code, (int)lst.size()); + last_svc_code = code; switch(code) { case EVENT_CACHE_INIT: resp = 0; @@ -39,6 +47,7 @@ void pub_serve_commands() break; case EVENT_CACHE_START: resp = 0; + lst_cache.swap(lst); lst.clear(); break; case EVENT_CACHE_STOP: @@ -47,7 +56,7 @@ void pub_serve_commands() break; case EVENT_CACHE_READ: resp = 0; - lst = { "rerer", "rrrr", "cccc" }; + lst.swap(lst_cache.empty() ? lst_read : lst_cache); break; case EVENT_ECHO: resp = 0; @@ -61,12 +70,19 @@ void pub_serve_commands() } service_svr.close_service(); EXPECT_FALSE(service_svr.is_active()); + terminate_svc = false; + last_svc_code = -1; + events_data_lst_t().swap(lst_cache); + events_data_lst_t().swap(lst_read); } string read_source; internal_event_t read_evt; +// #if 0 +static bool terminate_sub = false; + void run_sub() { void *mock_sub = zmq_socket (zmq_ctx, ZMQ_SUB); @@ -144,11 +160,9 @@ parse_read_evt(string &source, internal_event_t &evt, return ret; } - - TEST(events, publish) { - running_ut = 1; + // running_ut = 1; string evt_source0("sonic-events-bgp"); string evt_source1("sonic-events-xyz"); @@ -250,6 +264,238 @@ TEST(events, publish) events_deinit_publisher(h1); zmq_ctx_term(zmq_ctx); + zmq_ctx = NULL; + printf("************ PUBLISH DONE ***************\n"); +} +// #endif + +typedef struct { + int id; + string source; + string tag; + string rid; + string seq; + event_params_t params; + int missed_cnt; +} test_data_t; + +internal_event_t create_ev(const test_data_t &data) +{ + internal_event_t event_data; + + { + string param_str; + + EXPECT_EQ(0, serialize(data.params, param_str)); + + map_str_str_t event_str_map = { { data.source + ":" + data.tag, param_str}}; + + EXPECT_EQ(0, serialize(event_str_map, event_data[EVENT_STR_DATA])); + } + + event_data[EVENT_RUNTIME_ID] = data.rid; + event_data[EVENT_SEQUENCE] = data.seq; + + return event_data; +} + +static const test_data_t ldata[] = { + { + 0, + "source0", + "tag0", + "guid-0", + "1", + {{"ip", "10.10.10.10"}, {"state", "up"}}, + 0 + }, + { + 1, + "source0", + "tag1", + "guid-1", + "100", + {{"ip", "10.10.27.10"}, {"state", "down"}}, + 0 + }, + { + 2, + "source1", + "tag2", + "guid-2", + "101", + {{"ip", "10.10.24.10"}, {"state", "down"}}, + 0 + }, + { + 3, + "source0", + "tag3", + "guid-1", + "105", + {{"ip", "10.10.10.10"}, {"state", "up"}}, + 4 + }, + { + 4, + "source0", + "tag4", + "guid-0", + "2", + {{"ip", "10.10.20.10"}, {"state", "down"}}, + 0 + }, + { + 5, + "source1", + "tag5", + "guid-2", + "110", + {{"ip", "10.10.24.10"}, {"state", "down"}}, + 8 + }, + { + 6, + "source0", + "tag0", + "guid-0", + "5", + {{"ip", "10.10.10.10"}, {"state", "up"}}, + 2 + }, + { + 7, + "source0", + "tag1", + "guid-1", + "106", + {{"ip", "10.10.27.10"}, {"state", "down"}}, + 0 + }, + { + 8, + "source1", + "tag2", + "guid-2", + "111", + {{"ip", "10.10.24.10"}, {"state", "down"}}, + 0 + }, + { + 9, + "source0", + "tag3", + "guid-1", + "109", + {{"ip", "10.10.10.10"}, {"state", "up"}}, + 2 + }, + { + 10, + "source0", + "tag4", + "guid-0", + "6", + {{"ip", "10.10.20.10"}, {"state", "down"}}, + 0 + }, + { + 11, + "source1", + "tag5", + "guid-2", + "119", + {{"ip", "10.10.24.10"}, {"state", "down"}}, + 7 + }, +}; + +int pub_send_cnt = 0; + +void run_pub() +{ + /* + * Two ends of zmq had to be on different threads. + * so run it independently + */ + void *mock_pub; + mock_pub = zmq_socket (zmq_ctx, ZMQ_PUB); + EXPECT_TRUE(NULL != mock_pub); + EXPECT_EQ(0, zmq_bind(mock_pub, get_config(XPUB_END_KEY).c_str())); + + while (pub_send_cnt >= 0) { + if (pub_send_cnt == 0) { + this_thread::sleep_for(chrono::milliseconds(2)); + continue; + } + + /* Publish messages for deinit to capture */ + int i; + for(i=0; i 5); + + /* Ensure the counts are sane */ + EXPECT_TRUE(cnt_deinit_cache + cnt_active_cache > cnt_cache_overlap); + + thread thr_svc(&pub_serve_commands); + thread thr_pub(&run_pub); + + hsub = events_init_subscriber(true); + EXPECT_TRUE(NULL != hsub); + EXPECT_EQ(last_svc_code, EVENT_CACHE_STOP); + + /* Take a pause to allow publish to connect async */ + this_thread::sleep_for(chrono::milliseconds(200)); + + /* Publish messages for deinit to capture */ + pub_send_cnt = cnt_deinit_cache; + + /* Take a pause to ensure, subscriber would have got it */ + this_thread::sleep_for(chrono::milliseconds(200)); + + /* Verify all messages are sent/published */ + EXPECT_EQ(0, pub_send_cnt); + + events_deinit_subscriber(hsub); + EXPECT_TRUE(NULL == hsub); + EXPECT_EQ(last_svc_code, EVENT_CACHE_START); + EXPECT_TRUE(cnt_deinit_cache == (int)lst_cache.size()); + + events_deinit_subscriber(hsub); + + /* Don't need event's service anymore */ + terminate_svc = true; + pub_send_cnt = -1; + + thr_svc.join(); + thr_pub.join(); + zmq_ctx_term(zmq_ctx); } From e7f1bca54f54d3ef2745fc6432b348b97a4ba93b Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 31 May 2022 04:30:51 +0000 Subject: [PATCH 16/97] subscribe UT done --- common/events.cpp | 7 +- common/events_common.h | 13 ++-- tests/events_service_ut.cpp | 2 +- tests/events_ut.cpp | 124 +++++++++++++++++++++++++++--------- 4 files changed, 106 insertions(+), 40 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index e0cff70f9..a1b605a49 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -222,13 +222,16 @@ EventSubscriber::~EventSubscriber() chrono::steady_clock::time_point start = chrono::steady_clock::now(); while(true) { string source, evt_str; - rc = zmq_message_read(m_socket, ZMQ_DONTWAIT, source, evt_str); + internal_event_t evt_data; + + rc = zmq_message_read(m_socket, ZMQ_DONTWAIT, source, evt_data); if (rc == -1) { if (zerrno == EAGAIN) { rc = 0; } break; } + serialize(evt_data, evt_str); events.push_back(evt_str); chrono::steady_clock::time_point now = chrono::steady_clock::now(); if (chrono::duration_cast(now - start).count() > @@ -358,8 +361,8 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ else { if (m_track.size() > (MAX_PUBLISHERS_COUNT + 10)) { prune_track(); - m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); } + m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); } if (missed_cnt >= 0) { map_str_str_t ev; diff --git a/common/events_common.h b/common/events_common.h index b0907be28..7e00850dd 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -341,20 +341,21 @@ template int zmq_message_read(void *sock, int flag, P1 &pt1, P2 &pt2) { - int more = 0, rc, rc1; - - rc = zmq_read_part(sock, flag, more, pt1); + int more = 0, rc=-1, rc1, rc2 = 0; + + rc1 = zmq_read_part(sock, flag, more, pt1); if (more) { /* * read second part if more is set, irrespective * of any failure. More is set, only if sock is valid. */ - rc1 = zmq_read_part(sock, 0, more, pt2); + rc2 = zmq_read_part(sock, 0, more, pt2); } - RET_ON_ERR(rc == 0, "Failed to read part1"); - RET_ON_ERR(rc1 == 0, "Failed to read part2"); + RET_ON_ERR(rc1 == 0, "Failed to read part1"); + RET_ON_ERR(rc2 == 0, "Failed to read part2"); RET_ON_ERR(!more, "Don't expect more than 2 parts"); + rc = 0; out: return rc; } diff --git a/tests/events_service_ut.cpp b/tests/events_service_ut.cpp index 0bf01b649..efe83d0e0 100644 --- a/tests/events_service_ut.cpp +++ b/tests/events_service_ut.cpp @@ -29,7 +29,7 @@ void serve_commands() server_rd_code = code; server_rd_lst = lst; - printf("serve_commands code=%dlst=%d, %d\n", server_rd_code, (int)server_rd_lst.size(), (int)lst.size()); + // printf("serve_commands code=%dlst=%d, %d\n", server_rd_code, (int)server_rd_lst.size(), (int)lst.size()); switch(code) { case EVENT_CACHE_INIT: server_ret = 0; diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 30809d72a..2fa432bbb 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -18,12 +18,13 @@ int last_svc_code = -1; void events_validate_ts(const string s); -events_data_lst_t lst_cache, lst_read; +events_data_lst_t lst_cache; #define ARRAY_SIZE(d) (sizeof(d) / sizeof((d)[0])) static bool terminate_svc = false; + void pub_serve_commands() { event_service service_svr; @@ -38,7 +39,7 @@ void pub_serve_commands() /* check client service status, before blocking on read */ continue; } - printf("Read code=%d lst=%d\n", code, (int)lst.size()); + // printf("Read code=%d lst=%d\n", code, (int)lst.size()); last_svc_code = code; switch(code) { case EVENT_CACHE_INIT: @@ -56,7 +57,7 @@ void pub_serve_commands() break; case EVENT_CACHE_READ: resp = 0; - lst.swap(lst_cache.empty() ? lst_read : lst_cache); + lst.swap(lst_cache); break; case EVENT_ECHO: resp = 0; @@ -73,14 +74,12 @@ void pub_serve_commands() terminate_svc = false; last_svc_code = -1; events_data_lst_t().swap(lst_cache); - events_data_lst_t().swap(lst_read); } string read_source; internal_event_t read_evt; -// #if 0 static bool terminate_sub = false; void run_sub() @@ -132,16 +131,16 @@ parse_read_evt(string &source, internal_event_t &evt, EXPECT_EQ(1, m.size()); key = m.begin()->first; EXPECT_EQ(0, deserialize(m.begin()->second, params)); - cout << "EVENT_STR_DATA: " << e.second << "\n"; + // cout << "EVENT_STR_DATA: " << e.second << "\n"; } else if (e.first == EVENT_RUNTIME_ID) { rid = e.second; - cout << "EVENT_RUNTIME_ID: " << e.second << "\n"; + // cout << "EVENT_RUNTIME_ID: " << e.second << "\n"; } else if (e.first == EVENT_SEQUENCE) { stringstream ss(e.second); ss >> seq; - cout << "EVENT_SEQUENCE: " << seq << "\n"; + // cout << "EVENT_SEQUENCE: " << seq << "\n"; } else { EXPECT_FALSE(true); @@ -162,6 +161,7 @@ parse_read_evt(string &source, internal_event_t &evt, TEST(events, publish) { + // Enables all log messages to be printed, when this flag is set. // running_ut = 1; string evt_source0("sonic-events-bgp"); @@ -267,7 +267,6 @@ TEST(events, publish) zmq_ctx = NULL; printf("************ PUBLISH DONE ***************\n"); } -// #endif typedef struct { int id; @@ -410,6 +409,7 @@ static const test_data_t ldata[] = { }, }; +int pub_send_index = 0; int pub_send_cnt = 0; void run_pub() @@ -429,11 +429,10 @@ void run_pub() continue; } - /* Publish messages for deinit to capture */ int i; for(i=0; i= overlap_subs); + int index_subs = index_active_cache + cnt_active_cache - overlap_subs; + int cnt_subs = ARRAY_SIZE(ldata) - index_subs; + EXPECT_TRUE(cnt_subs > overlap_subs); event_handle_t hsub; zmq_ctx = zmq_ctx_new(); EXPECT_TRUE(NULL != zmq_ctx); - /* Ensure there are few more for active publiush to subscriber */ - EXPECT_TRUE(ARRAY_SIZE(ldata) - cnt_deinit_cache - cnt_active_cache > 5); - - /* Ensure the counts are sane */ - EXPECT_TRUE(cnt_deinit_cache + cnt_active_cache > cnt_cache_overlap); - thread thr_svc(&pub_serve_commands); thread thr_pub(&run_pub); @@ -471,23 +501,54 @@ TEST(events, subscribe) EXPECT_TRUE(NULL != hsub); EXPECT_EQ(last_svc_code, EVENT_CACHE_STOP); - /* Take a pause to allow publish to connect async */ - this_thread::sleep_for(chrono::milliseconds(200)); - /* Publish messages for deinit to capture */ - pub_send_cnt = cnt_deinit_cache; - - /* Take a pause to ensure, subscriber would have got it */ - this_thread::sleep_for(chrono::milliseconds(200)); - - /* Verify all messages are sent/published */ - EXPECT_EQ(0, pub_send_cnt); + pub_events(index_deinit_cache, cnt_deinit_cache); events_deinit_subscriber(hsub); EXPECT_TRUE(NULL == hsub); EXPECT_EQ(last_svc_code, EVENT_CACHE_START); EXPECT_TRUE(cnt_deinit_cache == (int)lst_cache.size()); + /* Publish messages for cache to capture with overlap */ + /* As we mimic cache service, add to the cache directly */ + for (i = 0; i < cnt_active_cache; ++i) { + string s; + internal_event_t evt(create_ev(ldata[index_active_cache+i])); + serialize(evt, s); + lst_cache.push_back(s); + } + EXPECT_EQ((int)lst_cache.size(), index_subs+overlap_subs); + + /* We publish all events ahead of receive, so set a timeout */ + hsub = events_init_subscriber(true, 100); + EXPECT_TRUE(NULL != hsub); + EXPECT_EQ(last_svc_code, EVENT_CACHE_STOP); + + pub_events(index_subs, cnt_subs); + + for(i=0; true; ++i) { + string key, exp_key; + event_params_t params; + int missed = -1; + + int rc = event_receive(hsub, key, params, missed); + + if (rc != 0) { + EXPECT_EQ(EAGAIN, event_last_error()); + break; + } + + EXPECT_EQ(ldata[i].params, params); + + exp_key = ldata[i].source + ":" + ldata[i].tag; + + EXPECT_EQ(exp_key, key); + + EXPECT_EQ(ldata[i].missed_cnt, missed); + } + + EXPECT_EQ(i, ARRAY_SIZE(ldata)); + events_deinit_subscriber(hsub); /* Don't need event's service anymore */ @@ -497,5 +558,6 @@ TEST(events, subscribe) thr_svc.join(); thr_pub.join(); zmq_ctx_term(zmq_ctx); + printf("************ SUBSCRIBE DONE ***************\n"); } From 94153f5195d10bc3f045c44bb9e53bb5a4ceafcd Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 31 May 2022 15:24:00 +0000 Subject: [PATCH 17/97] Drop internal readme --- common/COMPILE_README | 43 ------------------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 common/COMPILE_README diff --git a/common/COMPILE_README b/common/COMPILE_README deleted file mode 100644 index c0a4bd57e..000000000 --- a/common/COMPILE_README +++ /dev/null @@ -1,43 +0,0 @@ -1) Using ~/source/sonic-buildimage/c_build.sh -2) It uses _upd_cmn.sh to update files -3) On failure, go to ~/source/sonic-buildimage/target/debs/bullseye -4) open libswsscommon_1.0.0_amd64.deb.log - -Get failing command. Run from inside src/sonic-swss-common/common. Interestingly c compilation alone works fine outside slave too. -NOTE: From within slave you can't copy files from another repo as root of slave is at ~/src/sonic-buildimage - -/bin/bash ../libtool --tag=CXX --mode=compile g++ -DHAVE_CONFIG_H -I. -I.. -I .. -g -DNDEBUG -ansi -fPIC -std=c++11 -Wall -Wcast-align -Wcast-qual -Wconversion -Wdisabled-optimization -Werror -Wextra -Wfloat-equal -Wformat=2 -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winvalid-pch -Wlong-long -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wno-aggregate-return -Wno-padded -Wno-switch-enum -Wno-unused-parameter -Wpacked -Wpointer-arith -Wredundant-decls -Wshadow -Wstack-protector -Wstrict-aliasing=3 -Wswitch -Wswitch-default -Wunreachable-code -Wunused -Wvariadic-macros -Wno-write-strings -Wno-missing-format-attribute -Wno-long-long -Wdate-time -D_FORTIFY_SOURCE=2 -g -DNDEBUG -ansi -fPIC -std=c++11 -Wall -Wcast-align -Wcast-qual -Wconversion -Wdisabled-optimization -Werror -Wextra -Wfloat-equal -Wformat=2 -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winvalid-pch -Wlong-long -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wno-aggregate-return -Wno-padded -Wno-switch-enum -Wno-unused-parameter -Wpacked -Wpointer-arith -Wredundant-decls -Wshadow -Wstack-protector -Wstrict-aliasing=3 -Wswitch -Wswitch-default -Wunreachable-code -Wunused -Wvariadic-macros -Wno-write-strings -Wno-missing-format-attribute -Wno-long-long -I/usr/include/libnl3 -g -O2 -ffile-prefix-map=/sonic/src/sonic-swss-common=. -fstack-protector-strong -Wformat -Werror=format-security -c -o libswsscommon_la-events_common.lo `test -f 'events_common.cpp' || echo './'`events_common.cpp:wq - - - - - - -localadmin@c7cbc0ba3b64:/sonic$ cat c_build.sh -#! /bin/bash - -set -x - -./_upd_cmn.sh - -rm -f target/debs/bullseye/libswsscommon* -rm -f target/sonic-broadcom.bin target/sonic-aboot-broadcom.swi -# KEEP_SLAVE_ON=yes SONIC_BUILD_JOBS=7 PASSWORD=password make target/debs/bullseye/libswsscommon_1.0.0_amd64.deb -KEEP_SLAVE_ON=yes make target/debs/bullseye/libswsscommon_1.0.0_amd64.deb -# make target/debs/bullseye/libswsscommon_1.0.0_amd64.deb -#SONIC_BUILD_JOBS=7 PASSWORD=password make target/sonic-broadcom.bin -# SONIC_BUILD_JOBS=7 PASSWORD=password make target/sonic-aboot-broadcom.swi - - -localadmin@c7cbc0ba3b64:/sonic$ cat _upd_cmn.sh -#! /bin/bash - -SRCD="/home/localadmin/source/fork/syslog_telemetry/remanava/sonic-swss-common/common" -DSTD="./src/sonic-swss-common/common" - -for i in Makefile.am events.h events_common.cpp events_common.h -do - echo "copying $i" - cp ${SRCD}/$i ${DSTD}/$i -done -localadmin@c7cbc0ba3b64:/sonic$ From c4db46e2a770f6c77fbd0018d2b8b8fe148ecc0d Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 31 May 2022 16:21:09 +0000 Subject: [PATCH 18/97] Update upon self review - mostly on comments --- common/events.h | 34 +++++++++++----------------------- common/events_common.h | 21 +++++++-------------- common/events_pi.h | 13 +++++++++++++ 3 files changed, 31 insertions(+), 37 deletions(-) diff --git a/common/events.h b/common/events.h index 7360089ba..64445b456 100644 --- a/common/events.h +++ b/common/events.h @@ -6,12 +6,13 @@ * * APIs are for publishing & receiving events with source, tag and params along with timestamp. * Used by event publishers and those interested in receiving published events. - * Publishers are multiple sources, as processes running in hosts & containers. + * Publishers are multiple run from different contexts, as processes running in hosts & containers. * Receiver are often few. Telmetry container runs a receiver. * */ +/* Handle for a publisher / subscriber instance */ typedef void* event_handle_t; /* @@ -20,8 +21,6 @@ typedef void* event_handle_t; * A single publisher instance is maintained for a source. * Any duplicate init call for a source will return the same instance. * - * Choosing cache will help read cached data, during downtime, if any. - * * NOTE: * The initialization occurs asynchronously. * Any event published before init is complete, is blocked until the init @@ -47,7 +46,7 @@ event_handle_t events_init_publisher(const std::string event_source); * Handle returned from events_init_publisher * * Output: - * None + * Handle is nullified. */ void events_deinit_publisher(event_handle_t &handle); @@ -101,8 +100,6 @@ int event_publish(event_handle_t handle, const std::string event_tag, -typedef std::vector event_subscribe_sources_t; - /* * Initialize subscriber. * Init subscriber, optionally to filter by event-source. @@ -112,6 +109,7 @@ typedef std::vector event_subscribe_sources_t; * When set to true, it will make use of the cache service transparently. * The cache service caches events during session down time. The deinit * start the caching and init call stops the caching. + * default: false * * recv_timeout * Read blocks by default until an event is available for read. @@ -124,11 +122,14 @@ typedef std::vector event_subscribe_sources_t; * List of subscription sources of interest. * The source value is the corresponding YANG module name. * e.g. "sonic-events-bgp " is the source modulr name for bgp. + * default: All sources, if none provided. * * Return: * Non NULL handle on success * NULL on failure */ +typedef std::vector event_subscribe_sources_t; + event_handle_t events_init_subscriber(bool use_cache=false, int recv_timeout = -1, const event_subscribe_sources_t *sources=NULL); @@ -140,17 +141,18 @@ event_handle_t events_init_subscriber(bool use_cache=false, * Handle returned from events_init_subscriber * * Output: - * None + * Handle is nullified. */ void events_deinit_subscriber(event_handle_t &handle); + /* * Receive an event. - * A blocking call. + * A blocking call unless the subscriber is created with a timeout. * * This API maintains an expected sequence number and use the received * sequence in event to compute missed events count. The missed count - * set of events missed from this sender. + * provides the count of events missed from this sender. * * Received event: * It is a form of JSON struct, with a single key and @@ -198,18 +200,4 @@ int event_receive(event_handle_t handle, std::string &key, */ int event_last_error(); - -/* - * Cache drain timeout. - * - * When de-init is called, it calls stop cache service. - * But before this point, there could be events received in zmq's - * local cache pending read and those that arrived since last read. - * These events will not be seen by cache service. - * So read those off and give it to cache service as starting stock. - * As we don't have a clue on count in zmq's cache, read in non-block - * mode for a period. - */ -#define CACHE_DRAIN_IN_MILLISECS 1000 - #endif /* !_EVENTS_H */ diff --git a/common/events_common.h b/common/events_common.h index 7e00850dd..4d3bcf566 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -29,16 +29,15 @@ extern int recv_last_err; /* * Max count of possible concurrent event publishers - * A rough estimate only, more as a guideline than strict. - SWSS_LOG_ERROR(fmt.c_str(), e, zerrno __VA_OPT__(,) __VA_ARGS__); \ - * So this does not limit any usage + * We maintain a cache of last seen sequence number per publisher. + * This provides a MAX ceiling for cache. + * Any more publishers over this count should indicate a serious bug. */ #define MAX_PUBLISHERS_COUNT 1000 extern int running_ut; -/* TODO: Combine two SWSS_LOG_ERROR into one */ #define RET_ON_ERR(res, msg, ...)\ if (!(res)) {\ int _e = errno; \ @@ -50,9 +49,6 @@ extern int running_ut; printf("last:errno=%d zerr=%d\n", _e, zerrno); }\ goto out; } -#define ERR_CHECK(res, ...) {\ - if (!(res)) \ - SWSS_LOG_ERROR(__VA_ARGS__); } /* helper API to print variable type */ /* @@ -67,7 +63,6 @@ extern int running_ut; * std::cout << type_name() << '\n'; * std::cout << type_name() << '\n'; */ - template std::string type_name(); template @@ -102,6 +97,7 @@ get_typename(T &val) } +/* map to human readable str; Useful for error reporting. */ template string map_to_str(const Map &m) @@ -170,8 +166,8 @@ const string get_timestamp(); * Way to serialize map or vector * boost::archive::text_oarchive could be used to archive any struct/class * but that class needs some additional support, that declares - * boost::serialization::access as private friend and couple more tweaks - * std::map inherently supports serialization + * boost::serialization::access as private friend and couple more tweaks. + * The std::map & vector inherently supports serialization. */ template int @@ -249,9 +245,6 @@ zmsg_to_map(zmq_msg_t &msg, Map& data) * filter by source. * * Second part contains serialized form of map as defined in internal_event_t. - * The map is serialized and sent as string events_data_type_t. - * Caching that handles of set of events, handleas ordered events - * as declared in events_data_lst_t. */ /* * This is data going over wire and using cache. So be conservative @@ -274,7 +267,7 @@ typedef string runtime_id_t; * { EVENT_SEQUENCE, "" } }; */ -/* ZMQ message part 2 contains serialized version of internal_event_t */ +/* Cache maintains the part 2 of an event as serialized string. */ typedef string events_data_type_t; typedef vector events_data_lst_t; diff --git a/common/events_pi.h b/common/events_pi.h index 2079eb968..9f78b71c4 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -130,4 +130,17 @@ class EventSubscriber : public events_base }; +/* + * Cache drain timeout. + * + * When de-init is called, it calls stop cache service. + * But before this point, there could be events received in zmq's + * local cache pending read and those that arrived since last read. + * These events will not be seen by cache service. + * So read those off and give it to cache service as starting stock. + * As we don't have a clue on count in zmq's cache, read in non-block + * mode for a period. + */ +#define CACHE_DRAIN_IN_MILLISECS 1000 + #endif /* !_EVENTS_SERVICE_H */ From e81160bf2789a6c149e826fae696bc32fdef165e Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 31 May 2022 17:08:04 +0000 Subject: [PATCH 19/97] More on comments update --- common/events.cpp | 38 ++++++++++++++++++++++++-------------- common/events_pi.h | 30 ++++++++++++++++++++++-------- common/events_service.h | 26 ++++++++++++++++---------- 3 files changed, 62 insertions(+), 32 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index a1b605a49..03f3ca53f 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -38,16 +38,16 @@ typedef map lst_publishers_t; lst_publishers_t s_publishers; EventPublisher::EventPublisher() : - m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0), m_init(false) + m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0) { } int EventPublisher::init(const string event_source) { m_zmq_ctx = zmq_ctx_new(); - m_socket = zmq_socket (m_zmq_ctx, ZMQ_PUB); + void *sock = zmq_socket (m_zmq_ctx, ZMQ_PUB); - int rc = zmq_connect (m_socket, get_config(XSUB_END_KEY).c_str()); + int rc = zmq_connect (sock, get_config(XSUB_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Publisher fails to connect %s", get_config(XSUB_END_KEY).c_str()); // REQ socket is connected and a message is sent & received, more to @@ -72,15 +72,20 @@ int EventPublisher::init(const string event_source) uuid_unparse(id, uuid_str); m_runtime_id = string(uuid_str); - m_init = true; + m_socket = sock; out: - return m_init ? 0 : -1; + if (m_socket == NULL) { + zmq_close(sock); + } + return rc; } EventPublisher::~EventPublisher() { m_event_service.close_service(); - zmq_close(m_socket); + if (m_socket != NULL) { + zmq_close(m_socket); + } zmq_ctx_term(m_zmq_ctx); } @@ -190,7 +195,7 @@ event_publish(event_handle_t handle, const string tag, const event_params_t *par } -EventSubscriber::EventSubscriber() : m_zmq_ctx(NULL), m_socket(NULL), m_init(false), +EventSubscriber::EventSubscriber() : m_zmq_ctx(NULL), m_socket(NULL) m_cache_read(false) {}; @@ -245,7 +250,9 @@ EventSubscriber::~EventSubscriber() m_event_service.close_service(); } out: - zmq_close(m_socket); + if (m_socket == NULL) { + zmq_close(sock); + } zmq_ctx_term(m_zmq_ctx); } @@ -264,24 +271,24 @@ EventSubscriber::init(bool use_cache, int recv_timeout, */ m_zmq_ctx = zmq_ctx_new(); - m_socket = zmq_socket (m_zmq_ctx, ZMQ_SUB); + void *sock = zmq_socket (m_zmq_ctx, ZMQ_SUB); - int rc = zmq_connect (m_socket, get_config(XPUB_END_KEY).c_str()); + int rc = zmq_connect (sock, get_config(XPUB_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Subscriber fails to connect %s", get_config(XPUB_END_KEY).c_str()); if ((subs_sources == NULL) || (subs_sources->empty())) { - rc = zmq_setsockopt(m_socket, ZMQ_SUBSCRIBE, "", 0); + rc = zmq_setsockopt(sock, ZMQ_SUBSCRIBE, "", 0); RET_ON_ERR(rc == 0, "Fails to set option"); } else { for (const auto e: *subs_sources) { - rc = zmq_setsockopt(m_socket, ZMQ_SUBSCRIBE, e.c_str(), e.size()); + rc = zmq_setsockopt(sock, ZMQ_SUBSCRIBE, e.c_str(), e.size()); RET_ON_ERR(rc == 0, "Fails to set option"); } } if (recv_timeout != -1) { - rc = zmq_setsockopt (m_socket, ZMQ_RCVTIMEO, &recv_timeout, sizeof (recv_timeout)); + rc = zmq_setsockopt (sock, ZMQ_RCVTIMEO, &recv_timeout, sizeof (recv_timeout)); RET_ON_ERR(rc == 0, "Failed to ZMQ_RCVTIMEO to %d", recv_timeout); } @@ -294,8 +301,11 @@ EventSubscriber::init(bool use_cache, int recv_timeout, m_cache_read = true; } } - m_init = true; + m_socket = sock; out: + if (m_socket == NULL) { + zmq_close(sock); + } return rc; } diff --git a/common/events_pi.h b/common/events_pi.h index 9f78b71c4..ce334a62e 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -1,5 +1,5 @@ -#ifndef _EVENTS_SERVICE_H -#define _EVENTS_SERVICE_H +#ifndef _EVENTS_PI_H +#define _EVENTS_PI_H /* * Private header file used by events API implementation. * Required to run white box testing via unit tests. @@ -69,14 +69,17 @@ class EventPublisher : public events_base void *m_zmq_ctx; void *m_socket; + /* Event service - Used for echo */ event_service m_event_service; + /* Source YANG module for all events published by this instance */ string m_event_source; + /* Globally unique instance ID for this publishing instance */ runtime_id_t m_runtime_id; - sequence_t m_sequence; - bool m_init; + /* A running sequence number for events published by this instance */ + sequence_t m_sequence; }; /* @@ -104,14 +107,19 @@ class EventSubscriber : public events_base void *m_zmq_ctx; void *m_socket; + /* Service to use for cache management & echo */ event_service m_event_service; - bool m_init; + /* + * Set to true, upon cache read returning non zero count of events + * implying more to read. + */ bool m_cache_read; /* * Sequences tracked by sender for a source, or in other * words by runtime id. + * Epochtime, helps prune oldest, when cache overflows. */ typedef struct _evt_info { _evt_info() : epoch_secs(0), seq(0) {}; @@ -124,10 +132,16 @@ class EventSubscriber : public events_base typedef map track_info_t; track_info_t m_track; - events_data_lst_t m_from_cache; - + /* Prune the m_track, when goes beyond max - MAX_PUBLISHERS_COUNT */ void prune_track(); + + /* + * List of cached events. + * Only part 2 / internal_event_t is cached as serialized string. + */ + events_data_lst_t m_from_cache; + }; /* @@ -143,4 +157,4 @@ class EventSubscriber : public events_base */ #define CACHE_DRAIN_IN_MILLISECS 1000 -#endif /* !_EVENTS_SERVICE_H */ +#endif /* !_EVENTS_PI_H */ diff --git a/common/events_service.h b/common/events_service.h index d7d9f6848..39e8367c1 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -1,3 +1,6 @@ +#ifndef _EVENTS_SERVICE_H +#define _EVENTS_SERVICE_H + #include "string.h" #include "events_common.h" @@ -26,15 +29,17 @@ * * In case of echo, part2 is the vector of single string as provided in the request. * - * The read returns as serialized vector of ZMQ messages, in part2. + * The cache-read returns cached events as vector of serialized strings. + * NOTE: Cache only saves part 2 of the published event. */ +/* List of request codes for supported commands */ typedef enum { - EVENT_CACHE_INIT, - EVENT_CACHE_START, - EVENT_CACHE_STOP, - EVENT_CACHE_READ, - EVENT_ECHO + EVENT_CACHE_INIT, /* Init the cache before start */ + EVENT_CACHE_START, /* Start caching all published events */ + EVENT_CACHE_STOP, /* Stop the cache */ + EVENT_CACHE_READ, /* Read cached events */ + EVENT_ECHO /* Echoes the received data in request via response */ } event_req_type_t; @@ -64,7 +69,7 @@ class event_service { * its async connection to XPUB end point, but the eventd service * could be down. So having a timeout, helps which will timeout * recv. - * Publish clients that choose to block specify the duration + * Publish clients that choose to block may specify the duration * * Input: * zmq_ctx - Context to use @@ -156,7 +161,7 @@ class event_service { * * Internal details: * - * Cache service caches all events until buffer overflow + * Cache service caches all events until buffer overflow or max-ceil. * * Upon overflow, it creates a separate cache, where it keeps only * the last event received per runtime ID. @@ -168,9 +173,10 @@ class event_service { * output: * lst - A set of events, with a max cap. * Hence multiple reads may be required to read all. + * An empty list implies no more event in cache. * * return: - * 0 - On success. Either stopped or none to stop. + * 0 - On success. * -1 - On failure. */ int cache_read(events_data_lst_t &lst); @@ -277,4 +283,4 @@ class event_service { }; - +#endif // _EVENTS_SERVICE_H From 9f7b2a81e3ffdc57e3148ad92579aee508bcbb6e Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 31 May 2022 17:10:49 +0000 Subject: [PATCH 20/97] minor fix of copy/paste error --- common/events.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 03f3ca53f..2087b06b6 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -250,8 +250,8 @@ EventSubscriber::~EventSubscriber() m_event_service.close_service(); } out: - if (m_socket == NULL) { - zmq_close(sock); + if (m_socket != NULL) { + zmq_close(m_socket); } zmq_ctx_term(m_zmq_ctx); } From 35a6030d0e3d50b3ceec07ce78646e9d335e5617 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 31 May 2022 17:46:45 +0000 Subject: [PATCH 21/97] Comments update --- common/events.cpp | 57 +++++++++++++++------------------------ common/events_pi.h | 31 +++++++++++++++++++-- common/events_service.cpp | 37 ++++++++++++++----------- 3 files changed, 72 insertions(+), 53 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 2087b06b6..3a43b5ee8 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -1,36 +1,8 @@ #include "events_pi.h" -/* - * The uuid_unparse() function converts the supplied UUID uu from - * the binary representation into a 36-byte string (plus trailing - * '\0') of the form 1b4e28ba-2fa1-11d2-883f-0016d3cca427 and stores - * this value in the character string pointed to by out. - */ -#define UUID_STR_SIZE 40 - -/* - * Publisher use echo service and subscriber uses cache service - * The eventd process runs this service, which could be down - * All service interactions being async, a timeout is required - * not to block forever on read. - * - * The unit is in milliseconds in sync with ZMQ_RCVTIMEO of - * zmq_setsockopt. - * - * Publisher uses more to shadow async connectivity from PUB to - * XSUB end point of eventd's proxy. Hene have a less value. - * - * Subscriber uses it for cache management and here we need a - * longer timeout, to handle slow proxy. This timeout value's only - * impact could be subscriber process trying to terminate. - */ - -#define EVENTS_SERVICE_TIMEOUT_MS_PUB 200 -#define EVENTS_SERVICE_TIMEOUT_MS_SUB 2000 - /* * Track created publishers to avoid duplicates - * As we track missed event count by publishing instances, avoiding + * As receivers track missed event count by publishing instances, avoiding * duplicates helps reduce load. */ @@ -50,10 +22,6 @@ int EventPublisher::init(const string event_source) int rc = zmq_connect (sock, get_config(XSUB_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Publisher fails to connect %s", get_config(XSUB_END_KEY).c_str()); - // REQ socket is connected and a message is sent & received, more to - // ensure PUB socket had enough time to establish connection. - // Any message published before connection establishment is dropped. - // /* * Event service could be down. So have a timeout. * @@ -61,16 +29,26 @@ int EventPublisher::init(const string event_source) rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MS_PUB); RET_ON_ERR (rc == 0, "Failed to init event service"); + /* + * REQ socket is connected and a message is sent & received, more to + * ensure PUB socket had enough time to establish connection. + * Any message published before connection establishment is dropped. + * NOTE: We don't wait for response here, but read it upon first publish + * If the publisher init happened early at the start by caller, by the + * the first event is published, the echo response will be available locally. + */ rc = m_event_service.echo_send("hello"); RET_ON_ERR (rc == 0, "Failed to echo send in event service"); m_event_source = event_source; + { uuid_t id; char uuid_str[UUID_STR_SIZE]; uuid_generate(id); uuid_unparse(id, uuid_str); m_runtime_id = string(uuid_str); + } m_socket = sock; out: @@ -104,9 +82,12 @@ EventPublisher::publish(const string tag, const event_params_t *params) * as provided in publisher init. */ m_event_service.echo_receive(s); + + /* Close it as we don't need it anymore */ m_event_service.close_service(); } + /* Check for timestamp in params. If not, provide it. */ string param_str; event_params_t evt_params; if (params != NULL) { @@ -120,6 +101,7 @@ EventPublisher::publish(const string tag, const event_params_t *params) evt_params[event_ts_param] = get_timestamp(); params = &evt_params; } + rc = serialize(*params, param_str); RET_ON_ERR(rc == 0, "failed to serialize params %s", map_to_str(*params).c_str()); @@ -232,9 +214,12 @@ EventSubscriber::~EventSubscriber() rc = zmq_message_read(m_socket, ZMQ_DONTWAIT, source, evt_data); if (rc == -1) { if (zerrno == EAGAIN) { - rc = 0; + /* Try again after a small pause */ + this_thread::sleep_for(chrono::milliseconds(10)); + } + else { + break; } - break; } serialize(evt_data, evt_str); events.push_back(evt_str); @@ -315,10 +300,12 @@ EventSubscriber::prune_track() { map > lst; + /* Sort entries by last touched time */ for(const auto e: m_track) { lst[e.second.epoch_secs].push_back(e.first); } + /* By default it walks from lowest value / earliest timestamp */ map >::const_iterator itc = lst.begin(); for(; (itc != lst.end()) && (m_track.size() > MAX_PUBLISHERS_COUNT); ++itc) { for (const auto r: itc->second) { diff --git a/common/events_pi.h b/common/events_pi.h index ce334a62e..e52cb0700 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -111,8 +111,7 @@ class EventSubscriber : public events_base event_service m_event_service; /* - * Set to true, upon cache read returning non zero count of events - * implying more to read. + * Set to true, if there may be more events to read from cache. */ bool m_cache_read; @@ -157,4 +156,32 @@ class EventSubscriber : public events_base */ #define CACHE_DRAIN_IN_MILLISECS 1000 +/* + * The uuid_unparse() function converts the supplied UUID uu from + * the binary representation into a 36-byte string (plus trailing + * '\0') of the form 1b4e28ba-2fa1-11d2-883f-0016d3cca427 and stores + * this value in the character string pointed to by out. + */ +#define UUID_STR_SIZE 40 + +/* + * Publisher use echo service and subscriber uses cache service + * The eventd process runs this service, which could be down + * All service interactions being async, a timeout is required + * not to block forever on read. + * + * The unit is in milliseconds in sync with ZMQ_RCVTIMEO of + * zmq_setsockopt. + * + * Publisher uses more to shadow async connectivity from PUB to + * XSUB end point of eventd's proxy. Hence have a smaller value. + * + * Subscriber uses it for cache management and here we need a + * longer timeout, to handle slow proxy. This timeout value's only + * impact could be when subscriber process is trying to terminate. + */ + +#define EVENTS_SERVICE_TIMEOUT_MS_PUB 200 +#define EVENTS_SERVICE_TIMEOUT_MS_SUB 2000 + #endif /* !_EVENTS_PI_H */ diff --git a/common/events_service.cpp b/common/events_service.cpp index 0ff8a114b..762eccde2 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -1,25 +1,30 @@ #include "events_service.h" /* - * For brainstorming, if helpful - * The cache messages are read in either direction - * Upon start, the caller gives a set of events read for about 2 seconds - * in non-blocking mode to give it as start stock. + * Cache management * - * Upon cache stop, events collected MAX over a time is read by the caller. - * - * These messages are currently provided as vector list of strings. - * As cache start provided a small subset, it is given as part of start request - * Since cache read can be too many, multiple cache_Read requests are made - * until no more and each returns a subset as vector of strings. + * 1)` Caller expected to call init first, which initiates the connection + * to the capture end point. Being async, it would take some milliseconds + * to connect. * - * Another way, the entire cache in either direction can be sent/received - * via PAIR socket. But this woulkd need a special terminating message to - * indicate read end, as non-blocking read returning no event does not - * necessarily mean end + * 2) Caller starts the cache, optionally with some local cache it may have. + * The cache service keeps it as its startup/initial stock. + * This helps the caller saves his local cache with cache service. * - * Not sure, what the gain here is vs current approach of vector - * Just a note for now, not to lose a line of possibility. + * 3) Caller call stops, upon it making connect to XPUB end. + * As caller's connect is async and also this zmq end may have some cache + * of events by ZMQ locally. So read events little longer. + * + * 4) Upon stop, the caller may read cached events. + * The events are provided in FIFO order. + * As cached events can be too many, the service returns a few at a time. + * The caller is expected to read repeatedly until no event is returned. + * + * Cache overflow: + * A ceil is set and may run out of memory, before ceil is reached. + * In either case, the caching is *not* completely stopped but cached as + * one event per runtime-id/publishing instance. This info is required + * to compute missed message count due to overflow and otherwise. */ int From 6eb78d7119199b2e428da9547e89ae92fb44403c Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 31 May 2022 18:42:48 +0000 Subject: [PATCH 22/97] more comments --- tests/events_common_ut.cpp | 8 +++++++- tests/events_service_ut.cpp | 5 ++++- tests/events_ut.cpp | 9 +++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/events_common_ut.cpp b/tests/events_common_ut.cpp index 03a5ecf91..c3f03b436 100644 --- a/tests/events_common_ut.cpp +++ b/tests/events_common_ut.cpp @@ -56,6 +56,7 @@ TEST(events_common, ts) events_validate_ts(s); } +/* Tests serialize, deserialize, map_to_zmsg & zmsg_to_map */ TEST(events_common, msg) { map t = { @@ -76,9 +77,14 @@ TEST(events_common, msg) EXPECT_EQ(t, t1); } +/* + * Tests serialize, deserialize, map_to_zmsg, zmsg_to_map + * zmq_read_part & zmq_send_part while invoking zmq_message_send & + * zmq_message_read. + */ TEST(events_common, send_recv) { - running_ut = 1; + // running_ut = 1; char *path = "tcp://127.0.0.1:5570"; void *zmq_ctx = zmq_ctx_new(); diff --git a/tests/events_service_ut.cpp b/tests/events_service_ut.cpp index efe83d0e0..299eb83c3 100644 --- a/tests/events_service_ut.cpp +++ b/tests/events_service_ut.cpp @@ -16,6 +16,7 @@ static event_service service_cl, service_svr; static int server_rd_code, server_ret; static events_data_lst_t server_rd_lst, server_wr_lst; +/* Mimic the eventd service that handles service requests via dedicated thread */ void serve_commands() { int code; @@ -29,7 +30,6 @@ void serve_commands() server_rd_code = code; server_rd_lst = lst; - // printf("serve_commands code=%dlst=%d, %d\n", server_rd_code, (int)server_rd_lst.size(), (int)lst.size()); switch(code) { case EVENT_CACHE_INIT: server_ret = 0; @@ -71,6 +71,7 @@ TEST(events_common, cache_cmds) zmq_ctx = zmq_ctx_new(); EXPECT_TRUE(NULL != zmq_ctx); + /* Start mock service in a separate thread */ thread thr(&serve_commands); EXPECT_EQ(0, service_cl.init_client(zmq_ctx)); @@ -90,10 +91,12 @@ TEST(events_common, cache_cmds) EXPECT_EQ(0, service_cl.cache_start(lst_start)); EXPECT_EQ(EVENT_CACHE_START, server_rd_code); EXPECT_EQ(lst_start, server_rd_lst); + EXPECT_TRUE(server_wr_lst.empty()); EXPECT_EQ(0, service_cl.cache_stop()); EXPECT_EQ(EVENT_CACHE_STOP, server_rd_code); EXPECT_TRUE(server_rd_lst.empty()); + EXPECT_TRUE(server_wr_lst.empty()); EXPECT_EQ(0, service_cl.cache_read(lst)); EXPECT_EQ(EVENT_CACHE_READ, server_rd_code); diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 2fa432bbb..5c225a228 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -25,6 +25,7 @@ events_data_lst_t lst_cache; static bool terminate_svc = false; +/* Mock eventd service for cache & echo commands */ void pub_serve_commands() { event_service service_svr; @@ -82,6 +83,7 @@ internal_event_t read_evt; static bool terminate_sub = false; +/* Mock a subscriber for testing publisher APIs */ void run_sub() { void *mock_sub = zmq_socket (zmq_ctx, ZMQ_SUB); @@ -116,7 +118,7 @@ parse_read_evt(string &source, internal_event_t &evt, key.clear(); event_params_t().swap(params); - /* Pause with timeout for reading published message */ + /* Wait for run_sub to reads the published message with timeout. */ for(i=0; source.empty() && (i < 20); ++i) { this_thread::sleep_for(chrono::milliseconds(10)); } @@ -298,6 +300,7 @@ internal_event_t create_ev(const test_data_t &data) return event_data; } +/* Mock test data with event parameters and expected missed count */ static const test_data_t ldata[] = { { 0, @@ -412,6 +415,7 @@ static const test_data_t ldata[] = { int pub_send_index = 0; int pub_send_cnt = 0; +/* Mock publisher to test subscriber. Runs in dedicated thread */ void run_pub() { /* @@ -423,6 +427,7 @@ void run_pub() EXPECT_TRUE(NULL != mock_pub); EXPECT_EQ(0, zmq_bind(mock_pub, get_config(XPUB_END_KEY).c_str())); + /* Sends pub_send_cnt events from pub_send_index. */ while (pub_send_cnt >= 0) { if (pub_send_cnt == 0) { this_thread::sleep_for(chrono::milliseconds(2)); @@ -443,6 +448,7 @@ void run_pub() } +/* Helper API to publish via run_pub running in different thread. */ void pub_events(int index, int cnt) { /* Take a pause to allow publish to connect async */ @@ -475,7 +481,6 @@ TEST(events, subscribe) /* * Events published to active cache. - * Note a overlap with those published earlier for deinit */ int index_active_cache = index_deinit_cache + cnt_deinit_cache; int cnt_active_cache = 5; From 3328970f024e8b2e89dc5c14c163de9fb4417c18 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 31 May 2022 21:48:19 +0000 Subject: [PATCH 23/97] minor updates; merged with master via shared --- common/Makefile.am | 2 +- common/events.cpp | 8 +++++--- common/events_common.cpp | 18 ++++++++++++------ tests/Makefile.am | 3 +-- tests/events_common_ut.cpp | 3 ++- tests/events_ut.cpp | 4 ++-- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index 3be4acc1d..fb2ed6ec7 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -73,7 +73,7 @@ libswsscommon_la_SOURCES = \ libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS) -libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid -lboost_serialization +libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid swssloglevel_SOURCES = loglevel.cpp diff --git a/common/events.cpp b/common/events.cpp index 3a43b5ee8..eb90b7af5 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -177,7 +177,7 @@ event_publish(event_handle_t handle, const string tag, const event_params_t *par } -EventSubscriber::EventSubscriber() : m_zmq_ctx(NULL), m_socket(NULL) +EventSubscriber::EventSubscriber() : m_zmq_ctx(NULL), m_socket(NULL), m_cache_read(false) {}; @@ -221,8 +221,10 @@ EventSubscriber::~EventSubscriber() break; } } - serialize(evt_data, evt_str); - events.push_back(evt_str); + else { + serialize(evt_data, evt_str); + events.push_back(evt_str); + } chrono::steady_clock::time_point now = chrono::steady_clock::now(); if (chrono::duration_cast(now - start).count() > CACHE_DRAIN_IN_MILLISECS) diff --git a/common/events_common.cpp b/common/events_common.cpp index 6a77fdcb1..b9271ceea 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -8,7 +8,7 @@ int running_ut = 0; * defaults for all config entries */ #define CFG_VAL map_str_str_t::value_type -map_str_str_t cfg_data = { +const map_str_str_t cfg_default = { CFG_VAL(XSUB_END_KEY, "tcp://127.0.0.1:5570"), CFG_VAL(XPUB_END_KEY, "tcp://127.0.0.1:5571"), CFG_VAL(REQ_REP_END_KEY, "tcp://127.0.0.1:5572"), @@ -17,12 +17,21 @@ map_str_str_t cfg_data = { CFG_VAL(CACHE_MAX_CNT, "") }; +map_str_str_t cfg_data; + void read_init_config(const char *init_cfg_file) { + /* Set default and override from file */ + cfg_data = cfg_default; + + if (init_cfg_file == NULL) { + return; + } + ifstream fs (init_cfg_file); - if (!fs.is_open()) + if (!fs.is_open()) return; stringstream buffer; @@ -49,11 +58,8 @@ read_init_config(const char *init_cfg_file) string get_config(const string key) { - static bool init = false; - - if (!init) { + if (cfg_data.empty()) { read_init_config(INIT_CFG_PATH); - init = true; } /* Intentionally crash for non-existing key, as this * is internal code bug diff --git a/tests/Makefile.am b/tests/Makefile.am index db11cdcd2..663540340 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -36,7 +36,6 @@ tests_SOURCES = redis_ut.cpp \ status_code_util_test.cpp \ saiaclschema_ut.cpp \ timer_ut.cpp \ - cli_ut.cpp \ events_common_ut.cpp \ events_service_ut.cpp \ events_ut.cpp \ @@ -44,4 +43,4 @@ tests_SOURCES = redis_ut.cpp \ tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) -tests_LDADD = $(LDADD_GTEST) -lpthread -L$(top_srcdir)/common -lswsscommon $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -L$(top_srcdir)/sonic-db-cli -lsonicdbcli -lzmq -luuid -lboost_serialization +tests_LDADD = $(LDADD_GTEST) -lpthread -L$(top_srcdir)/common -lswsscommon $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -luuid -lboost_serialization diff --git a/tests/events_common_ut.cpp b/tests/events_common_ut.cpp index c3f03b436..b4e5fc64a 100644 --- a/tests/events_common_ut.cpp +++ b/tests/events_common_ut.cpp @@ -37,7 +37,8 @@ TEST(events_common, get_config) EXPECT_EQ(100, get_config_data(CACHE_MAX_CNT, 100)); - cout << "events_common: get_config succeeded\n"; + read_init_config(NULL); + EXPECT_EQ(string("tcp://127.0.0.1:5570"), get_config(string(XSUB_END_KEY))); } void diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 5c225a228..36c8795ef 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -164,7 +164,7 @@ parse_read_evt(string &source, internal_event_t &evt, TEST(events, publish) { // Enables all log messages to be printed, when this flag is set. - // running_ut = 1; + running_ut = 0; string evt_source0("sonic-events-bgp"); string evt_source1("sonic-events-xyz"); @@ -469,7 +469,7 @@ TEST(events, subscribe) { int i; // Enables all log messages to be printed, when this flag is set. - // running_ut = 1; + running_ut = 0; /* From 66632f6c4c6ec8fa675ba6d77011c92a36c4c19d Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 2 Jun 2022 16:05:13 +0000 Subject: [PATCH 24/97] Per review comments --- common/events.cpp | 28 ++++++++++++++-------------- common/events_common.cpp | 6 +++--- common/events_common.h | 26 +++++++++++++------------- common/events_pi.h | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index eb90b7af5..01a874ed9 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -205,7 +205,11 @@ EventSubscriber::~EventSubscriber() /* Shadow the cache init request, as it is async */ m_event_service.send_recv(EVENT_ECHO); - /* read for 2 seconds in non-block mode, to drain any local cache */ + /* + * read for a second in non-block mode, to drain any local cache. + * Break if no event locally available or 1 second passed, whichever + * comes earlier. + */ chrono::steady_clock::time_point start = chrono::steady_clock::now(); while(true) { string source, evt_str; @@ -214,19 +218,15 @@ EventSubscriber::~EventSubscriber() rc = zmq_message_read(m_socket, ZMQ_DONTWAIT, source, evt_data); if (rc == -1) { if (zerrno == EAGAIN) { - /* Try again after a small pause */ - this_thread::sleep_for(chrono::milliseconds(10)); - } - else { - break; + rc = 0; } + break; } - else { - serialize(evt_data, evt_str); - events.push_back(evt_str); - } + + serialize(evt_data, evt_str); + events.push_back(evt_str); chrono::steady_clock::time_point now = chrono::steady_clock::now(); - if (chrono::duration_cast(now - start).count() > + if (chrono::duration_cast(now - start).count() > CACHE_DRAIN_IN_MILLISECS) break; } @@ -399,12 +399,12 @@ events_init_subscriber(bool use_cache, int recv_timeout, const event_subscribe_sources_t *sources) { if (s_subscriber == NULL) { - EventSubscriber *p = new EventSubscriber(); + EventSubscriber *sub = new EventSubscriber(); - RET_ON_ERR(p->init(use_cache, recv_timeout, sources) == 0, + RET_ON_ERR(sub->init(use_cache, recv_timeout, sources) == 0, "Failed to init subscriber"); - s_subscriber = p; + s_subscriber = sub; } out: return s_subscriber; diff --git a/common/events_common.cpp b/common/events_common.cpp index b9271ceea..34ea32755 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -70,11 +70,11 @@ get_config(const string key) const string get_timestamp() { - std::stringstream ss, sfrac; + stringstream ss, sfrac; auto timepoint = system_clock::now(); - std::time_t tt = system_clock::to_time_t (timepoint); - struct std::tm * ptm = std::localtime(&tt); + time_t tt = system_clock::to_time_t (timepoint); + struct tm * ptm = localtime(&tt); uint64_t ms = duration_cast(timepoint.time_since_epoch()).count(); uint64_t sec = duration_cast(timepoint.time_since_epoch()).count(); diff --git a/common/events_common.h b/common/events_common.h index 4d3bcf566..12479d67c 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -63,34 +63,34 @@ extern int running_ut; * std::cout << type_name() << '\n'; * std::cout << type_name() << '\n'; */ -template std::string type_name(); +template string type_name(); template -std::string +string type_name() { - typedef typename std::remove_reference::type TR; - std::unique_ptr own + typedef typename remove_reference::type TR; + unique_ptr own ( abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr), - std::free + free ); - std::string r = own != nullptr ? own.get() : typeid(TR).name(); - if (std::is_const::value) + string r = own != nullptr ? own.get() : typeid(TR).name(); + if (is_const::value) r += " const"; - if (std::is_volatile::value) + if (is_volatile::value) r += " volatile"; - if (std::is_lvalue_reference::value) + if (is_lvalue_reference::value) r += "&"; - else if (std::is_rvalue_reference::value) + else if (is_rvalue_reference::value) r += "&&"; return r; } template -std::string +string get_typename(T &val) { return type_name(); @@ -174,7 +174,7 @@ int serialize(const Map& data, string &s) { s.clear(); - std::stringstream _ser_ss; + stringstream _ser_ss; boost::archive::text_oarchive oarch(_ser_ss); try { @@ -195,7 +195,7 @@ template int deserialize(const string& s, Map& data) { - std::stringstream ss(s); + stringstream ss(s); boost::archive::text_iarchive iarch(ss); try { diff --git a/common/events_pi.h b/common/events_pi.h index e52cb0700..23b9fbf01 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -62,7 +62,7 @@ class EventPublisher : public events_base int init(const string event_source); - int publish(const std::string event_tag, + int publish(const string event_tag, const event_params_t *params); private: From 9ba11ed0fe3909483cdd673c4bf61f80f78ccd42 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 7 Jun 2022 17:48:50 +0000 Subject: [PATCH 25/97] minor updates --- common/events.cpp | 2 +- common/events_common.cpp | 18 ++++++++++++++++++ common/events_common.h | 11 ++++------- common/events_pi.h | 17 ----------------- common/logger.h | 2 +- tests/events_common_ut.cpp | 8 +++++++- tests/events_service_ut.cpp | 9 ++++++++- tests/events_ut.cpp | 23 +++++++++++++++-------- 8 files changed, 54 insertions(+), 36 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 01a874ed9..d13e0a1fe 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -350,7 +350,7 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ /* Find any missed events for this runtime ID */ missed_cnt = 0; - sequence_t seq = events_base::str_to_seq(event_data[EVENT_SEQUENCE]); + sequence_t seq = str_to_seq(event_data[EVENT_SEQUENCE]); track_info_t::iterator it = m_track.find(event_data[EVENT_RUNTIME_ID]); if (it != m_track.end()) { /* current seq - last read - 1 == 0 if none missed */ diff --git a/common/events_common.cpp b/common/events_common.cpp index 34ea32755..716d4407f 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -19,6 +19,24 @@ const map_str_str_t cfg_default = { map_str_str_t cfg_data; +sequence_t str_to_seq(const string s) +{ + stringstream ss(s); + sequence_t seq; + + ss >> seq; + + return seq; +} + +string seq_to_str(sequence_t seq) +{ + stringstream ss; + ss << seq; + return ss.str(); +} + + void read_init_config(const char *init_cfg_file) { diff --git a/common/events_common.h b/common/events_common.h index 12479d67c..b962324ee 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -35,18 +35,12 @@ extern int recv_last_err; */ #define MAX_PUBLISHERS_COUNT 1000 -extern int running_ut; - - #define RET_ON_ERR(res, msg, ...)\ if (!(res)) {\ int _e = errno; \ zerrno = zmq_errno(); \ SWSS_LOG_ERROR(msg, ##__VA_ARGS__); \ SWSS_LOG_ERROR("last:errno=%d zerr=%d", _e, zerrno); \ - if (running_ut) { \ - printf(msg, ##__VA_ARGS__); \ - printf("last:errno=%d zerr=%d\n", _e, zerrno); }\ goto out; } @@ -105,7 +99,7 @@ map_to_str(const Map &m) stringstream _ss; _ss << "{"; for (const auto elem: m) { - _ss << "{" << elem.first << "," << elem.second << "}"; + _ss << "{" << elem.first << "," << elem.second.substr(0,10) << "}"; } _ss << "}"; return _ss.str(); @@ -272,6 +266,9 @@ typedef string events_data_type_t; typedef vector events_data_lst_t; +sequence_t str_to_seq(const string s); +string seq_to_str(sequence_t seq); + template int zmq_read_part(void *sock, int flag, int &more, DT &data) diff --git a/common/events_pi.h b/common/events_pi.h index 23b9fbf01..6189bd35a 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -27,23 +27,6 @@ class events_base public: virtual ~events_base() = default; - static sequence_t str_to_seq(const string s) - { - stringstream ss(s); - sequence_t seq; - - ss >> seq; - - return seq; - } - - static string seq_to_str(sequence_t seq) - { - stringstream ss; - ss << seq; - return ss.str(); - } - }; /* diff --git a/common/logger.h b/common/logger.h index 1f541bc81..79fdec47f 100644 --- a/common/logger.h +++ b/common/logger.h @@ -102,6 +102,7 @@ class Logger static std::string priorityToString(Priority prio); static std::string outputToString(Output output); + static void swssOutputNotify(const std::string& component, const std::string& outputStr); class ScopeLogger { @@ -141,7 +142,6 @@ class Logger Logger& operator=(const Logger&); static void swssPrioNotify(const std::string& component, const std::string& prioStr); - static void swssOutputNotify(const std::string& component, const std::string& outputStr); void settingThread(); void terminateSettingThread(); diff --git a/tests/events_common_ut.cpp b/tests/events_common_ut.cpp index b4e5fc64a..e8c16a549 100644 --- a/tests/events_common_ut.cpp +++ b/tests/events_common_ut.cpp @@ -85,7 +85,13 @@ TEST(events_common, msg) */ TEST(events_common, send_recv) { - // running_ut = 1; +#if 0 + { + /* Direct log messages to stdout */ + string dummy, op("STDOUT"); + swss::Logger::swssOutputNotify(dummy, op); + } +#endif char *path = "tcp://127.0.0.1:5570"; void *zmq_ctx = zmq_ctx_new(); diff --git a/tests/events_service_ut.cpp b/tests/events_service_ut.cpp index 299eb83c3..623cdeff1 100644 --- a/tests/events_service_ut.cpp +++ b/tests/events_service_ut.cpp @@ -66,7 +66,14 @@ void serve_commands() TEST(events_common, cache_cmds) { events_data_lst_t lst_start, lst; - running_ut = 1; + +#if 0 + { + /* Direct log messages to stdout */ + string dummy, op("STDOUT"); + swss::Logger::swssOutputNotify(dummy, op); + } +#endif zmq_ctx = zmq_ctx_new(); EXPECT_TRUE(NULL != zmq_ctx); diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 36c8795ef..0fdabd1eb 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -94,7 +94,7 @@ void run_sub() EXPECT_TRUE(NULL != mock_sub); EXPECT_EQ(0, zmq_bind(mock_sub, get_config(XSUB_END_KEY).c_str())); EXPECT_EQ(0, zmq_setsockopt(mock_sub, ZMQ_SUBSCRIBE, "", 0)); - EXPECT_EQ(0, zmq_setsockopt(mock_sub, ZMQ_RCVTIMEO, &block_ms, sizeof (block_ms, 0))); + EXPECT_EQ(0, zmq_setsockopt(mock_sub, ZMQ_RCVTIMEO, &block_ms, sizeof (block_ms))); while(!terminate_sub) { if (0 == zmq_message_read(mock_sub, 0, source, ev_int)) { @@ -163,8 +163,11 @@ parse_read_evt(string &source, internal_event_t &evt, TEST(events, publish) { - // Enables all log messages to be printed, when this flag is set. - running_ut = 0; + { + /* Direct log messages to stdout */ + string dummy, op("STDOUT"); + swss::Logger::swssOutputNotify(dummy, op); + } string evt_source0("sonic-events-bgp"); string evt_source1("sonic-events-xyz"); @@ -468,9 +471,13 @@ void pub_events(int index, int cnt) TEST(events, subscribe) { int i; - // Enables all log messages to be printed, when this flag is set. - running_ut = 0; - +#if 0 + { + /* Direct log messages to stdout */ + string dummy, op("STDOUT"); + swss::Logger::swssOutputNotify(dummy, op); + } +#endif /* * Events published during subs deinit, which will be provided @@ -491,7 +498,7 @@ TEST(events, subscribe) int overlap_subs = 3; EXPECT_TRUE(cnt_active_cache >= overlap_subs); int index_subs = index_active_cache + cnt_active_cache - overlap_subs; - int cnt_subs = ARRAY_SIZE(ldata) - index_subs; + int cnt_subs = ((int)ARRAY_SIZE(ldata)) - index_subs; EXPECT_TRUE(cnt_subs > overlap_subs); event_handle_t hsub; @@ -552,7 +559,7 @@ TEST(events, subscribe) EXPECT_EQ(ldata[i].missed_cnt, missed); } - EXPECT_EQ(i, ARRAY_SIZE(ldata)); + EXPECT_EQ(i, (int)ARRAY_SIZE(ldata)); events_deinit_subscriber(hsub); From d1a6f835747cfaf158c63ed6391a488c719b8ea0 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 9 Jun 2022 04:42:21 +0000 Subject: [PATCH 26/97] minor: name change for a typedef --- common/events.cpp | 7 ++++--- common/events_common.h | 35 ++++++++++++++++++++++++++++++----- common/events_pi.h | 15 +-------------- common/events_service.cpp | 20 ++++++++++---------- common/events_service.h | 16 ++++++++-------- tests/events_common_ut.cpp | 1 + tests/events_service_ut.cpp | 9 +++++---- tests/events_ut.cpp | 8 +++++--- 8 files changed, 64 insertions(+), 47 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index d13e0a1fe..ef850ffda 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -197,7 +197,7 @@ EventSubscriber::~EventSubscriber() int rc = 0; if (m_event_service.is_active()) { - events_data_lst_t events; + event_serialized_lst_t events; rc = m_event_service.cache_init(); RET_ON_ERR(rc == 0, "Failed to init the cache"); @@ -212,7 +212,8 @@ EventSubscriber::~EventSubscriber() */ chrono::steady_clock::time_point start = chrono::steady_clock::now(); while(true) { - string source, evt_str; + string source; + event_serialized_t evt_str; internal_event_t evt_data; rc = zmq_message_read(m_socket, ZMQ_DONTWAIT, source, evt_data); @@ -335,7 +336,7 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ if (!m_from_cache.empty()) { - events_data_lst_t::iterator it = m_from_cache.begin(); + event_serialized_lst_t::iterator it = m_from_cache.begin(); rc = deserialize(*it, event_data); m_from_cache.erase(it); RET_ON_ERR(rc == 0, "Failed to deserialize message from cache"); diff --git a/common/events_common.h b/common/events_common.h index b962324ee..e2c0c6d64 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -261,9 +261,11 @@ typedef string runtime_id_t; * { EVENT_SEQUENCE, "" } }; */ +typedef vector internal_events_lst_t; + /* Cache maintains the part 2 of an event as serialized string. */ -typedef string events_data_type_t; -typedef vector events_data_lst_t; +typedef string event_serialized_t; // events_data_type_t; +typedef vector event_serialized_lst_t; // events_data_lst_t; sequence_t str_to_seq(const string s); @@ -278,9 +280,11 @@ zmq_read_part(void *sock, int flag, int &more, DT &data) more = 0; zmq_msg_init(&msg); int rc = zmq_msg_recv(&msg, sock, flag); - recv_last_err = zerrno; - - if (rc != -1) { + if (rc == -1) { + recv_last_err = zerrno; + } + else { + recv_last_err = 0; size_t more_size = sizeof (more); rc = zmsg_to_map(msg, data); @@ -350,4 +354,25 @@ zmq_message_read(void *sock, int flag, P1 &pt1, P2 &pt2) return rc; } +/* + * Cache drain timeout. + * + * When subscriber's de-init is called, it calls start cache service. + * When subscriber init is called, it calls cache stop service. + * + * In either scenario, an entity stops reading and let other start. + * The entity that stops may have to read little longer to drain any + * events in local ZMQ cache. + * + * This timeout helps with that. + * + * In case of subscriber de-init, the events read during this period + * is given to cache as start-up or initial stock. + * In case of init where cache service reads for this period, gives + * those as part of cache read and subscriber service will be diligent + * about reading the same event from the channel, hence duplicate + * for next one second. + */ +#define CACHE_DRAIN_IN_MILLISECS 1000 + #endif /* !_EVENTS_COMMON_H */ diff --git a/common/events_pi.h b/common/events_pi.h index 6189bd35a..46552654b 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -122,23 +122,10 @@ class EventSubscriber : public events_base * List of cached events. * Only part 2 / internal_event_t is cached as serialized string. */ - events_data_lst_t m_from_cache; + event_serialized_lst_t m_from_cache; }; -/* - * Cache drain timeout. - * - * When de-init is called, it calls stop cache service. - * But before this point, there could be events received in zmq's - * local cache pending read and those that arrived since last read. - * These events will not be seen by cache service. - * So read those off and give it to cache service as starting stock. - * As we don't have a clue on count in zmq's cache, read in non-block - * mode for a period. - */ -#define CACHE_DRAIN_IN_MILLISECS 1000 - /* * The uuid_unparse() function converts the supplied UUID uu from * the binary representation into a 36-byte string (plus trailing diff --git a/common/events_service.cpp b/common/events_service.cpp index 762eccde2..722ccf42c 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -73,7 +73,7 @@ event_service::init_server(void *zmq_ctx, int block_ms) int event_service::echo_send(const string s) { - events_data_lst_t l = { s }; + event_serialized_lst_t l = { s }; return channel_write(EVENT_ECHO, l); @@ -83,7 +83,7 @@ event_service::echo_send(const string s) int event_service::echo_receive(string &outs) { - events_data_lst_t l; + event_serialized_lst_t l; int code; int rc = channel_read(code, l); @@ -112,7 +112,7 @@ event_service::cache_init() int -event_service::cache_start(const events_data_lst_t &lst) +event_service::cache_start(const event_serialized_lst_t &lst) { int rc; @@ -136,7 +136,7 @@ event_service::cache_stop() int -event_service::cache_read(events_data_lst_t &lst) +event_service::cache_read(event_serialized_lst_t &lst) { int rc; @@ -148,25 +148,25 @@ event_service::cache_read(events_data_lst_t &lst) int -event_service::channel_read(int &code, events_data_lst_t &data) +event_service::channel_read(int &code, event_serialized_lst_t &data) { - events_data_lst_t().swap(data); + event_serialized_lst_t().swap(data); return zmq_message_read(m_socket, 0, code, data); } int -event_service::channel_write(int code, const events_data_lst_t &data) +event_service::channel_write(int code, const event_serialized_lst_t &data) { return zmq_message_send(m_socket, code, data); } int -event_service::send_recv(int code, const events_data_lst_t *lst_in, - events_data_lst_t *lst_out) +event_service::send_recv(int code, const event_serialized_lst_t *lst_in, + event_serialized_lst_t *lst_out) { - events_data_lst_t l; + event_serialized_lst_t l; int resp; if(lst_in == NULL) { diff --git a/common/events_service.h b/common/events_service.h index 39e8367c1..8bb3788c9 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -25,7 +25,7 @@ * In case of data, it comes in seccond part. * * Type of data is one or multiple strings, which is sent as serialized vector - * of strings. events_data_lst_t + * of strings. event_serialized_lst_t * * In case of echo, part2 is the vector of single string as provided in the request. * @@ -133,7 +133,7 @@ class event_service { * 1 - Already running * -1 - On failure. */ - int cache_start(const events_data_lst_t &lst); + int cache_start(const event_serialized_lst_t &lst); /* * Called to stop caching events @@ -179,7 +179,7 @@ class event_service { * 0 - On success. * -1 - On failure. */ - int cache_read(events_data_lst_t &lst); + int cache_read(event_serialized_lst_t &lst); /* * Echo send service. @@ -231,7 +231,7 @@ class event_service { * 0 - On success * -1 - On failure */ - int channel_read(int &code, events_data_lst_t &data); + int channel_read(int &code, event_serialized_lst_t &data); /* * The under lying write for req/resp from client/server @@ -247,12 +247,12 @@ class event_service { * 0 - On success * -1 - On failure */ - int channel_write(int code, const events_data_lst_t &data); + int channel_write(int code, const event_serialized_lst_t &data); /* * send and receive helper. * Writes given code & data and reads back data into - * provided events_data_lst_t arg and response read is + * provided event_serialized_lst_t arg and response read is * returned. * * input: @@ -265,8 +265,8 @@ class event_service { * return: * Any failure or response code from server. */ - int send_recv(int code, const events_data_lst_t *lst_in = NULL, - events_data_lst_t *lst_out = NULL); + int send_recv(int code, const event_serialized_lst_t *lst_in = NULL, + event_serialized_lst_t *lst_out = NULL); /* * de-init/close service diff --git a/tests/events_common_ut.cpp b/tests/events_common_ut.cpp index e8c16a549..cffac53fc 100644 --- a/tests/events_common_ut.cpp +++ b/tests/events_common_ut.cpp @@ -90,6 +90,7 @@ TEST(events_common, send_recv) /* Direct log messages to stdout */ string dummy, op("STDOUT"); swss::Logger::swssOutputNotify(dummy, op); + swss::Logger::setMinPrio(swss::Logger::SWSS_DEBUG); } #endif diff --git a/tests/events_service_ut.cpp b/tests/events_service_ut.cpp index 623cdeff1..734ce9c55 100644 --- a/tests/events_service_ut.cpp +++ b/tests/events_service_ut.cpp @@ -14,13 +14,13 @@ static bool do_terminate = false; static void *zmq_ctx = NULL; static event_service service_cl, service_svr; static int server_rd_code, server_ret; -static events_data_lst_t server_rd_lst, server_wr_lst; +static event_serialized_lst_t server_rd_lst, server_wr_lst; /* Mimic the eventd service that handles service requests via dedicated thread */ void serve_commands() { int code; - events_data_lst_t lst; + event_serialized_lst_t lst; EXPECT_EQ(0, service_svr.init_server(zmq_ctx, 1000)); while(!do_terminate) { if (0 != service_svr.channel_read(code, lst)) { @@ -65,13 +65,14 @@ void serve_commands() TEST(events_common, cache_cmds) { - events_data_lst_t lst_start, lst; + event_serialized_lst_t lst_start, lst; #if 0 { /* Direct log messages to stdout */ string dummy, op("STDOUT"); swss::Logger::swssOutputNotify(dummy, op); + swss::Logger::setMinPrio(swss::Logger::SWSS_DEBUG); } #endif @@ -93,7 +94,7 @@ TEST(events_common, cache_cmds) * Bunch of serialized internal_event_t as strings * Sending random for test purpose */ - lst_start = events_data_lst_t( + lst_start = event_serialized_lst_t( { "hello", "world", "ok" }); EXPECT_EQ(0, service_cl.cache_start(lst_start)); EXPECT_EQ(EVENT_CACHE_START, server_rd_code); diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 0fdabd1eb..39dd52877 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -18,7 +18,7 @@ int last_svc_code = -1; void events_validate_ts(const string s); -events_data_lst_t lst_cache; +event_serialized_lst_t lst_cache; #define ARRAY_SIZE(d) (sizeof(d) / sizeof((d)[0])) @@ -34,7 +34,7 @@ void pub_serve_commands() EXPECT_EQ(0, service_svr.init_server(zmq_ctx, 1000)); while(!terminate_svc) { int code, resp; - events_data_lst_t lst; + event_serialized_lst_t lst; if (0 != service_svr.channel_read(code, lst)) { /* check client service status, before blocking on read */ @@ -74,7 +74,7 @@ void pub_serve_commands() EXPECT_FALSE(service_svr.is_active()); terminate_svc = false; last_svc_code = -1; - events_data_lst_t().swap(lst_cache); + event_serialized_lst_t().swap(lst_cache); } @@ -167,6 +167,7 @@ TEST(events, publish) /* Direct log messages to stdout */ string dummy, op("STDOUT"); swss::Logger::swssOutputNotify(dummy, op); + swss::Logger::setMinPrio(swss::Logger::SWSS_DEBUG); } string evt_source0("sonic-events-bgp"); @@ -476,6 +477,7 @@ TEST(events, subscribe) /* Direct log messages to stdout */ string dummy, op("STDOUT"); swss::Logger::swssOutputNotify(dummy, op); + swss::Logger::setMinPrio(swss::Logger::SWSS_DEBUG); } #endif From bd28ea81ba677385e6e7a67c54feec348ed433ea Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 10 Jun 2022 16:07:48 +0000 Subject: [PATCH 27/97] Added EXIT code --- common/events_service.cpp | 2 +- common/events_service.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/events_service.cpp b/common/events_service.cpp index 722ccf42c..8b86eba79 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -183,7 +183,7 @@ event_service::send_recv(int code, const event_serialized_lst_t *lst_in, RET_ON_ERR(rc == 0, "failing to read resp for code=%d", code); rc = resp; - RET_ON_ERR (rc == 0, "echo receive resp %d not 0 for code=%d", resp, code); + RET_ON_ERR (rc == 0, "receive resp %d not 0 for code=%d", resp, code); out: return rc; diff --git a/common/events_service.h b/common/events_service.h index 8bb3788c9..f0931d0a8 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -39,7 +39,8 @@ typedef enum { EVENT_CACHE_START, /* Start caching all published events */ EVENT_CACHE_STOP, /* Stop the cache */ EVENT_CACHE_READ, /* Read cached events */ - EVENT_ECHO /* Echoes the received data in request via response */ + EVENT_ECHO, /* Echoes the received data in request via response */ + EVENT_EXIT /* Exit the eventd service -- Useful for unit test.*/ } event_req_type_t; From 8f722589a1ac9edb1163de15aabded8c5a9216bc Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 14 Jun 2022 15:58:32 +0000 Subject: [PATCH 28/97] Minor name change; Enabled py build for events --- common/events.cpp | 8 ++++---- common/events.h | 6 +++++- common/events_common.cpp | 1 - common/events_common.h | 15 +++++---------- pyext/swsscommon.i | 2 ++ tests/events_ut.cpp | 6 +++--- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index ef850ffda..6e7056ffd 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -91,14 +91,14 @@ EventPublisher::publish(const string tag, const event_params_t *params) string param_str; event_params_t evt_params; if (params != NULL) { - if (params->find(event_ts_param) == params->end()) { + if (params->find(EVENT_TS_PARAM) == params->end()) { evt_params = *params; - evt_params[event_ts_param] = get_timestamp(); + evt_params[EVENT_TS_PARAM] = get_timestamp(); params = &evt_params; } } else { - evt_params[event_ts_param] = get_timestamp(); + evt_params[EVENT_TS_PARAM] = get_timestamp(); params = &evt_params; } @@ -436,6 +436,6 @@ event_receive(event_handle_t handle, string &key, int event_last_error() { - return recv_last_err; + return zerrno; } diff --git a/common/events.h b/common/events.h index 64445b456..a23aae9fc 100644 --- a/common/events.h +++ b/common/events.h @@ -1,6 +1,10 @@ #ifndef _EVENTS_H #define _EVENTS_H +#include +#include +#include + /* * Events library * @@ -59,7 +63,7 @@ typedef std::map event_params_t; /* * timestamp param name */ -const std::string event_ts_param("timestamp"); +#define EVENT_TS_PARAM "timestamp" /* * Publish an event diff --git a/common/events_common.cpp b/common/events_common.cpp index 716d4407f..714a48a60 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -1,7 +1,6 @@ #include "events_common.h" int zerrno = 0; -int recv_last_err = 0; int running_ut = 0; /* diff --git a/common/events_common.h b/common/events_common.h index e2c0c6d64..27ca4cec9 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -25,7 +25,6 @@ using namespace chrono; extern int errno; extern int zerrno; -extern int recv_last_err; /* * Max count of possible concurrent event publishers @@ -169,9 +168,9 @@ serialize(const Map& data, string &s) { s.clear(); stringstream _ser_ss; - boost::archive::text_oarchive oarch(_ser_ss); try { + boost::archive::text_oarchive oarch(_ser_ss); oarch << data; s = _ser_ss.str(); return 0; @@ -189,17 +188,17 @@ template int deserialize(const string& s, Map& data) { - stringstream ss(s); - boost::archive::text_iarchive iarch(ss); try { + stringstream ss(s); + boost::archive::text_iarchive iarch(ss); iarch >> data; return 0; } catch (exception& e) { stringstream _ss_ex; - _ss_ex << e.what() << "str[0:32]:" << s.substr(0, 32) << " data type: " + _ss_ex << e.what() << "str[0:64]:" << s.substr(0, 64) << " data type: " << get_typename(data); SWSS_LOG_ERROR("deserialize Failed: %s", _ss_ex.str().c_str()); return -1; @@ -280,11 +279,7 @@ zmq_read_part(void *sock, int flag, int &more, DT &data) more = 0; zmq_msg_init(&msg); int rc = zmq_msg_recv(&msg, sock, flag); - if (rc == -1) { - recv_last_err = zerrno; - } - else { - recv_last_err = 0; + if (rc != -1) { size_t more_size = sizeof (more); rc = zmsg_to_map(msg, data); diff --git a/pyext/swsscommon.i b/pyext/swsscommon.i index f3b15cd22..a9d5925f4 100644 --- a/pyext/swsscommon.i +++ b/pyext/swsscommon.i @@ -35,6 +35,7 @@ #include "notificationproducer.h" #include "warm_restart.h" #include "logger.h" +#include "events.h" #include "configdb.h" #include "status_code_util.h" %} @@ -206,4 +207,5 @@ T castSelectableObj(swss::Selectable *temp) %include "warm_restart.h" %include "dbinterface.h" %include "logger.h" +%include "events.h" %include "status_code_util.h" diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 39dd52877..cff99a0aa 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -202,7 +202,7 @@ TEST(events, publish) EXPECT_EQ(seq0, 1); EXPECT_EQ(rd_key0, evt_source0 + ":" + evt_tag0); - it_param = rd_params0.find(event_ts_param); + it_param = rd_params0.find(EVENT_TS_PARAM); EXPECT_TRUE(it_param != rd_params0.end()); if (it_param != rd_params0.end()) { events_validate_ts(it_param->second); @@ -221,7 +221,7 @@ TEST(events, publish) EXPECT_EQ(seq1, 2); EXPECT_EQ(rd_key1, evt_source0 + ":" + evt_tag1); - it_param = rd_params1.find(event_ts_param); + it_param = rd_params1.find(EVENT_TS_PARAM); EXPECT_TRUE(it_param != rd_params1.end()); if (it_param != rd_params1.end()) { events_validate_ts(it_param->second); @@ -247,7 +247,7 @@ TEST(events, publish) EXPECT_EQ(seq0, 1); EXPECT_EQ(rd_key0, evt_source1 + ":" + evt_tag0); - it_param = rd_params0.find(event_ts_param); + it_param = rd_params0.find(EVENT_TS_PARAM); EXPECT_TRUE(it_param != rd_params0.end()); if (it_param != rd_params0.end()) { events_validate_ts(it_param->second); From ce606d439056fc0bb5d2ef2336c054d2ba1c5db6 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 17 Jun 2022 22:35:42 +0000 Subject: [PATCH 29/97] Minor signature update to adapt to SWIG generated python --- common/events.cpp | 17 ++++++++++++----- common/events.h | 29 +++++++++++++++++++++++++++-- common/events_common.h | 7 ++++++- pyext/swsscommon.i | 2 ++ 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 6e7056ffd..5551be2a1 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -149,7 +149,7 @@ events_init_publisher(const string event_source) } void -events_deinit_publisher(event_handle_t &handle) +events_deinit_publisher(event_handle_t handle) { lst_publishers_t::iterator it; @@ -160,8 +160,6 @@ events_deinit_publisher(event_handle_t &handle) break; } } - handle = NULL; - } int @@ -413,13 +411,12 @@ events_init_subscriber(bool use_cache, int recv_timeout, void -events_deinit_subscriber(event_handle_t &handle) +events_deinit_subscriber(event_handle_t handle) { if ((handle == s_subscriber) && (s_subscriber != NULL)) { delete s_subscriber; s_subscriber = NULL; } - handle = NULL; } @@ -434,6 +431,16 @@ event_receive(event_handle_t handle, string &key, return -1; } + +event_receive_op_t +event_receive_wrap(event_handle_t handle) +{ + event_receive_op_t op; + + op.rc = event_receive(handle, op.key, op.params, op.missed_cnt); + return op; +} + int event_last_error() { return zerrno; diff --git a/common/events.h b/common/events.h index a23aae9fc..577470c04 100644 --- a/common/events.h +++ b/common/events.h @@ -52,7 +52,7 @@ event_handle_t events_init_publisher(const std::string event_source); * Output: * Handle is nullified. */ -void events_deinit_publisher(event_handle_t &handle); +void events_deinit_publisher(event_handle_t handle); /* @@ -147,7 +147,7 @@ event_handle_t events_init_subscriber(bool use_cache=false, * Output: * Handle is nullified. */ -void events_deinit_subscriber(event_handle_t &handle); +void events_deinit_subscriber(event_handle_t handle); /* @@ -194,6 +194,31 @@ void events_deinit_subscriber(event_handle_t &handle); int event_receive(event_handle_t handle, std::string &key, event_params_t ¶ms, int &missed_cnt); +/* + * event_receive_wrap + * + * Returns o/p as structured. + * This is handy for invocation via python. + * + * input: + * handle - As obtained from events_init_subscriber + * + * output: + * None + * + * Return: + * struct that gets return value and all o/p params of event_receive + */ +typedef struct { + int rc; /* Return value of event_receive */ + /* o/p params from event receive */ + std::string key; + event_params_t params; + int missed_cnt; +} event_receive_op_t; + +event_receive_op_t event_receive_wrap(event_handle_t handle); + /* * Get error code for last receive diff --git a/common/events_common.h b/common/events_common.h index 27ca4cec9..6bbb7fe69 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -96,9 +96,14 @@ string map_to_str(const Map &m) { stringstream _ss; + string sep; + _ss << "{"; for (const auto elem: m) { - _ss << "{" << elem.first << "," << elem.second.substr(0,10) << "}"; + _ss << sep << "{" << elem.first << "," << elem.second.substr(0,10) << "}"; + if (sep.empty()) { + sep = ", "; + } } _ss << "}"; return _ss.str(); diff --git a/pyext/swsscommon.i b/pyext/swsscommon.i index a9d5925f4..87b8d79a2 100644 --- a/pyext/swsscommon.i +++ b/pyext/swsscommon.i @@ -208,4 +208,6 @@ T castSelectableObj(swss::Selectable *temp) %include "dbinterface.h" %include "logger.h" %include "events.h" +%ignore event_receive(event_handle_t, std::string &, event_params_t &, int &); + %include "status_code_util.h" From b0d7ee088ab594c20a75e97c6b40238186337ff5 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Mon, 20 Jun 2022 23:00:59 +0000 Subject: [PATCH 30/97] Made zmq send & receive thread safe --- common/events.cpp | 13 +- common/events.h | 22 ++- common/events_common.cpp | 1 - common/events_common.h | 314 +++++++++++++++++++++---------------- tests/events_common_ut.cpp | 21 --- tests/events_ut.cpp | 3 +- 6 files changed, 195 insertions(+), 179 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 5551be2a1..111d68ea4 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -215,10 +215,8 @@ EventSubscriber::~EventSubscriber() internal_event_t evt_data; rc = zmq_message_read(m_socket, ZMQ_DONTWAIT, source, evt_data); - if (rc == -1) { - if (zerrno == EAGAIN) { - rc = 0; - } + if (rc != 0) { + /* Break on any failure, including EAGAIN */ break; } @@ -344,7 +342,7 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ /* Read from SUBS channel */ string evt_source; rc = zmq_message_read(m_socket, 0, evt_source, event_data); - RET_ON_ERR(rc == 0, "Failed to read message from sock"); + RET_ON_ERR(rc == 0, "Failed to read message from sock rc=%d", rc); } /* Find any missed events for this runtime ID */ @@ -441,8 +439,3 @@ event_receive_wrap(event_handle_t handle) return op; } -int event_last_error() -{ - return zerrno; -} - diff --git a/common/events.h b/common/events.h index 577470c04..6a45c754d 100644 --- a/common/events.h +++ b/common/events.h @@ -96,8 +96,9 @@ typedef std::map event_params_t; * e.g. "2022-08-17T02:39:21.286611Z" * * return: - * 0 - On success - * -1 - On failure. + * 0 - On success + * > 0 - On failure, returns zmq_errno, if failure is zmq socket related. + * < 0 - For all other failures */ int event_publish(event_handle_t handle, const std::string event_tag, const event_params_t *params=NULL); @@ -187,8 +188,9 @@ void events_deinit_subscriber(event_handle_t handle); * missed count from all received events will give the total missed. * * return: - * 0 - On success - * -1 - On failure. The handle is not valid or upon receive timeout. + * 0 - On success + * > 0 - On failure, returns zmq_errno, if failure is zmq socket related. + * < 0 - For all other failures * */ int event_receive(event_handle_t handle, std::string &key, @@ -219,14 +221,8 @@ typedef struct { event_receive_op_t event_receive_wrap(event_handle_t handle); - -/* - * Get error code for last receive - * - * Set to EAGAIN on timeout - * Any other value implies fatal error. - * - */ -int event_last_error(); +/* Non ZMQ Error codes */ +#define ERR_MESSAGE_INVALID -2 +#define ERR_OTHER -1 #endif /* !_EVENTS_H */ diff --git a/common/events_common.cpp b/common/events_common.cpp index 714a48a60..0f3ad20ad 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -1,6 +1,5 @@ #include "events_common.h" -int zerrno = 0; int running_ut = 0; /* diff --git a/common/events_common.h b/common/events_common.h index 6bbb7fe69..753c934ee 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -23,9 +23,6 @@ using namespace std; using namespace chrono; -extern int errno; -extern int zerrno; - /* * Max count of possible concurrent event publishers * We maintain a cache of last seen sequence number per publisher. @@ -37,9 +34,8 @@ extern int zerrno; #define RET_ON_ERR(res, msg, ...)\ if (!(res)) {\ int _e = errno; \ - zerrno = zmq_errno(); \ SWSS_LOG_ERROR(msg, ##__VA_ARGS__); \ - SWSS_LOG_ERROR("last:errno=%d zerr=%d", _e, zerrno); \ + SWSS_LOG_ERROR("last:errno=%d", _e); \ goto out; } @@ -160,83 +156,6 @@ T get_config_data(const string key, T def) const string get_timestamp(); -/* - * Way to serialize map or vector - * boost::archive::text_oarchive could be used to archive any struct/class - * but that class needs some additional support, that declares - * boost::serialization::access as private friend and couple more tweaks. - * The std::map & vector inherently supports serialization. - */ -template -int -serialize(const Map& data, string &s) -{ - s.clear(); - stringstream _ser_ss; - - try { - boost::archive::text_oarchive oarch(_ser_ss); - oarch << data; - s = _ser_ss.str(); - return 0; - } - catch (exception& e) { - stringstream _ser_ex_ss; - - _ser_ex_ss << e.what() << "map type:" << get_typename(data); - SWSS_LOG_ERROR("serialize Failed: %s", _ser_ex_ss.str().c_str()); - return -1; - } -} - -template -int -deserialize(const string& s, Map& data) -{ - - try { - stringstream ss(s); - boost::archive::text_iarchive iarch(ss); - iarch >> data; - return 0; - } - catch (exception& e) { - stringstream _ss_ex; - - _ss_ex << e.what() << "str[0:64]:" << s.substr(0, 64) << " data type: " - << get_typename(data); - SWSS_LOG_ERROR("deserialize Failed: %s", _ss_ex.str().c_str()); - return -1; - } -} - - -template -int -map_to_zmsg(const Map& data, zmq_msg_t &msg) -{ - string s; - int rc = serialize(data, s); - - if (rc == 0) { - rc = zmq_msg_init_size(&msg, s.size()); - } - if (rc == 0) { - strncpy((char *)zmq_msg_data(&msg), s.c_str(), s.size()); - } - return rc; -} - - -template -int -zmsg_to_map(zmq_msg_t &msg, Map& data) -{ - string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); - return deserialize(s, data); -} - - /* * events are published as two part zmq message. * First part only has the event source, so receivers could @@ -275,83 +194,214 @@ typedef vector event_serialized_lst_t; // events_data_lst_t; sequence_t str_to_seq(const string s); string seq_to_str(sequence_t seq); -template -int -zmq_read_part(void *sock, int flag, int &more, DT &data) +struct serialization { - zmq_msg_t msg; + /* + * Way to serialize map or vector + * boost::archive::text_oarchive could be used to archive any struct/class + * but that class needs some additional support, that declares + * boost::serialization::access as private friend and couple more tweaks. + * The std::map & vector inherently supports serialization. + */ + template + int + serialize(const Map& data, string &s) + { + s.clear(); + ostringstream _ser_ss; + + try { + boost::archive::text_oarchive oarch(_ser_ss); + oarch << data; + s = _ser_ss.str(); + return 0; + } + catch (exception& e) { + stringstream _ser_ex_ss; + + _ser_ex_ss << e.what() << "map type:" << get_typename(data); + SWSS_LOG_ERROR("serialize Failed: %s", _ser_ex_ss.str().c_str()); + return ERR_MESSAGE_INVALID; + } + } - more = 0; - zmq_msg_init(&msg); - int rc = zmq_msg_recv(&msg, sock, flag); - if (rc != -1) { - size_t more_size = sizeof (more); + template + int + deserialize(const string& s, Map& data) + { - rc = zmsg_to_map(msg, data); + try { + istringstream ss(s); + boost::archive::text_iarchive iarch(ss); + iarch >> data; + return 0; + } + catch (exception& e) { + stringstream _ss_ex; + + _ss_ex << e.what() << "str[0:64]:(" << s.substr(0, 64) << ") data type: " + << get_typename(data); + SWSS_LOG_ERROR("deserialize Failed: %s", _ss_ex.str().c_str()); + return ERR_MESSAGE_INVALID; + } + } - /* read more flag if message read fails to de-serialize */ - zmq_getsockopt (sock, ZMQ_RCVMORE, &more, &more_size); + template + int + map_to_zmsg(const Map& data, zmq_msg_t &msg) + { + string s; + int rc = serialize(data, s); + if (rc == 0) { + rc = zmq_msg_init_size(&msg, s.size()); + } + if (rc == 0) { + strncpy((char *)zmq_msg_data(&msg), s.c_str(), s.size()); + } + return rc; } - zmq_msg_close(&msg); - return rc; -} - -template + template + int + zmsg_to_map(zmq_msg_t &msg, Map& data) + { + string s((const char *)zmq_msg_data(&msg), zmq_msg_size(&msg)); + return deserialize(s, data); + } + + + template + int + zmq_read_part(void *sock, int flag, int &more, DT &data) + { + zmq_msg_t msg; + + more = 0; + zmq_msg_init(&msg); + int rc = zmq_msg_recv(&msg, sock, flag); + if (rc != -1) { + size_t more_size = sizeof (more); + + zmq_getsockopt (sock, ZMQ_RCVMORE, &more, &more_size); + + rc = zmsg_to_map(msg, data); + RET_ON_ERR(rc == 0, "Failed to deserialize part rc=%d", rc); + /* read more flag if message read fails to de-serialize */ + } + else { + /* override with zmq err */ + rc = zmq_errno(); + RET_ON_ERR(false, "Failed to read part rc=%d", rc); + } + out: + zmq_msg_close(&msg); + + return rc; + } + + + template + int + zmq_send_part(void *sock, int flag, const DT &data) + { + zmq_msg_t msg; + + int rc = map_to_zmsg(data, msg); + RET_ON_ERR(rc == 0, "Failed to map to zmsg %d", rc); + + rc = zmq_msg_send (&msg, sock, flag); + if (rc == -1) { + /* override with zmq err */ + rc = zmq_errno(); + RET_ON_ERR(false, "Failed to send part %d", rc); + } + /* zmq_msg_send returns count of bytes sent */ + rc = 0; + out: + zmq_msg_close(&msg); + return rc; + } + + template + int + zmq_message_send(void *sock, const P1 &pt1, const P2 &pt2) + { + int rc = zmq_send_part(sock, pt2.empty() ? 0 : ZMQ_SNDMORE, pt1); + + /* send second part, only if first is sent successfully */ + if ((rc == 0) && (!pt2.empty())) { + rc = zmq_send_part(sock, 0, pt2); + } + return rc; + } + + + template + int + zmq_message_read(void *sock, int flag, P1 &pt1, P2 &pt2) + { + int more = 0, rc, rc2 = 0; + + rc = zmq_read_part(sock, flag, more, pt1); + + if (more) { + /* + * read second part if more is set, irrespective + * of any failure. More is set, only if sock is valid. + */ + rc2 = zmq_read_part(sock, 0, more, pt2); + } + RET_ON_ERR(rc == 0, "Failed to read part1"); + if (rc2 != 0) { + rc = rc2; + RET_ON_ERR(false, "Failed to read part2"); + } + if (more) { + rc = -1; + RET_ON_ERR(false, "Don't expect more than 2 parts"); + } + out: + return rc; + } + +}; + +template int -zmq_send_part(void *sock, int flag, const DT &data) +serialize(const Map& data, string &s) { - zmq_msg_t msg; + auto render = boost::serialization::singleton::get_const_instance(); - int rc = map_to_zmsg(data, msg); - RET_ON_ERR(rc == 0, "Failed to map to zmsg %d", rc); + return render.serialize(data, s); +} - rc = zmq_msg_send (&msg, sock, flag); - RET_ON_ERR(rc != -1, "Failed to send part %d", rc); +template +int +deserialize(const string& s, Map& data) +{ + auto render = boost::serialization::singleton::get_const_instance(); - rc = 0; -out: - zmq_msg_close(&msg); - return rc; + return render.deserialize(s, data); } template int zmq_message_send(void *sock, const P1 &pt1, const P2 &pt2) { - int rc = zmq_send_part(sock, pt2.empty() ? 0 : ZMQ_SNDMORE, pt1); + auto render = boost::serialization::singleton::get_const_instance(); - /* send second part, only if first is sent successfully */ - if ((rc == 0) && (!pt2.empty())) { - rc = zmq_send_part(sock, 0, pt2); - } - return rc; + return render.zmq_message_send(sock, pt1, pt2); } - template int zmq_message_read(void *sock, int flag, P1 &pt1, P2 &pt2) { - int more = 0, rc=-1, rc1, rc2 = 0; + auto render = boost::serialization::singleton::get_const_instance(); - rc1 = zmq_read_part(sock, flag, more, pt1); - - if (more) { - /* - * read second part if more is set, irrespective - * of any failure. More is set, only if sock is valid. - */ - rc2 = zmq_read_part(sock, 0, more, pt2); - } - RET_ON_ERR(rc1 == 0, "Failed to read part1"); - RET_ON_ERR(rc2 == 0, "Failed to read part2"); - RET_ON_ERR(!more, "Don't expect more than 2 parts"); - rc = 0; -out: - return rc; + return render.zmq_message_read(sock, flag, pt1, pt2); } /* diff --git a/tests/events_common_ut.cpp b/tests/events_common_ut.cpp index cffac53fc..7df48588b 100644 --- a/tests/events_common_ut.cpp +++ b/tests/events_common_ut.cpp @@ -57,27 +57,6 @@ TEST(events_common, ts) events_validate_ts(s); } -/* Tests serialize, deserialize, map_to_zmsg & zmsg_to_map */ -TEST(events_common, msg) -{ - map t = { - { "foo", "bar" }, - { "test", "5" }, - { "hello", "world" } }; - - map t1; - - zmq_msg_t msg; - - map_to_zmsg(t, msg); - - EXPECT_NE(t, t1); - - zmsg_to_map(msg, t1); - - EXPECT_EQ(t, t1); -} - /* * Tests serialize, deserialize, map_to_zmsg, zmsg_to_map * zmq_read_part & zmq_send_part while invoking zmq_message_send & diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index cff99a0aa..686b08bc7 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -519,7 +519,6 @@ TEST(events, subscribe) pub_events(index_deinit_cache, cnt_deinit_cache); events_deinit_subscriber(hsub); - EXPECT_TRUE(NULL == hsub); EXPECT_EQ(last_svc_code, EVENT_CACHE_START); EXPECT_TRUE(cnt_deinit_cache == (int)lst_cache.size()); @@ -548,7 +547,7 @@ TEST(events, subscribe) int rc = event_receive(hsub, key, params, missed); if (rc != 0) { - EXPECT_EQ(EAGAIN, event_last_error()); + EXPECT_EQ(EAGAIN, rc); break; } From ee8e79e268dc549f3594f10db9ef8820d0700f60 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 5 Jul 2022 15:19:16 +0000 Subject: [PATCH 31/97] temp commit to enable merge --- common/events.cpp | 169 ++++++++++++++++++++++++++++++++++++++++++- common/events.h | 6 +- common/events_wrap.h | 152 ++++++++++++++++++++++++++++++++++++++ tests/events_ut.cpp | 2 +- 4 files changed, 324 insertions(+), 5 deletions(-) create mode 100644 common/events_wrap.h diff --git a/common/events.cpp b/common/events.cpp index 111d68ea4..b48dee1c4 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -1,4 +1,5 @@ #include "events_pi.h" +#include "events_wrap.h" /* * Track created publishers to avoid duplicates @@ -431,7 +432,7 @@ event_receive(event_handle_t handle, string &key, event_receive_op_t -event_receive_wrap(event_handle_t handle) +event_receive_as_struct(event_handle_t handle) { event_receive_op_t op; @@ -439,3 +440,169 @@ event_receive_wrap(event_handle_t handle) return op; } +void * +events_init_publisher_wrap(const char *args) +{ + SWSS_LOG_DEBUG("events_init_publisher_wrap: args=%s", + (args != NULL ? args : "")); + + if (args == NULL) { + return NULL; + } + const auto &data = nlohmann::json::parse(args); + + string source; + for (auto it = data.cbegin(); it != data.cend(); ++it) { + if ((it.key() == ARGS_SOURCE) && (*it).is_string()) { + source = it.value(); + } + } + return events_init_publisher(source); +} + + +void +events_deinit_publisher_wrap(void *handle) +{ + events_deinit_publisher(handle); +} + + +int +event_publish_wrap(void *handle, const char *args) +{ + string tag; + event_params_t params; + + SWSS_LOG_DEBUG("events_init_publisher_wrap: handle=%p args=%s", + handle, (args != NULL ? args : "")); + + if (args == NULL) { + return -1; + } + const auto &data = nlohmann::json::parse(args); + + for (auto it = data.cbegin(); it != data.cend(); ++it) { + if ((it.key() == ARGS_TAG) && (*it).is_string()) { + tag = it.value(); + } + else if ((it.key() == ARGS_PARAMS) && (*it).is_object()) { + const auto ¶ms_data = *it; + for (auto itp = params_data.cbegin(); itp != params_data.cend(); ++itp) { + if ((*itp).is_string()) { + params[itp.key()] = itp.value(); + } + } + } + } + return event_publish(handle, tag, ¶ms); +} + +void * +events_init_subscriber_wrap(const char *args) +{ + bool use_cache = true; + int recv_timeout = -1; + event_subscribe_sources_t sources; + + SWSS_LOG_DEBUG("events_init_subsriber_wrap: args:%s", args); + + if (args != NULL) { + const auto &data = nlohmann::json::parse(args); + + for (auto it = data.cbegin(); it != data.cend(); ++it) { + if ((it.key() == ARGS_USE_CACHE) && (*it).is_boolean()) { + use_cache = it.value(); + } + else if ((it.key() == ARGS_RECV_TIMEOUT) && (*it).is_number_integer()) { + recv_timeout = it.value(); + } + } + } + void *h = events_init_subscriber(use_cache, recv_timeout); + SWSS_LOG_DEBUG("events_init_subscriber_wrap: handle=%p", h); + return h; +} + + +void +events_deinit_subscriber_wrap(void *handle) +{ + SWSS_LOG_DEBUG("events_deinit_subsriber_wrap: args=%p", handle); + + events_deinit_subscriber(handle); +} + + +int +event_receive_wrap(void *handle, char *event_str, + int event_str_sz, char *missed_cnt_str, int missed_cnt_str_sz) +{ + string key; + event_params_t params; + int missed_cnt = 0; + + SWSS_LOG_DEBUG("events_receive_wrap h=%p event-sz=%d missed-sz=%d\n", + handle, event_str_sz, missed_cnt_str_sz); + + int rc = event_receive(handle, key, params, missed_cnt); + + if (rc == 0) { + nlohmann::json res = nlohmann::json::object(); + + { + nlohmann::json params_data = nlohmann::json::object(); + + for (event_params_t::const_iterator itc = params.begin(); itc != params.end(); ++itc) { + params_data[itc->first] = itc->second; + } + res[key] = params_data; + } + string json_str(res.dump()); + rc = snprintf(event_str, event_str_sz, "%s", json_str.c_str()); + + int rc_missed = snprintf(missed_cnt_str, missed_cnt_str_sz, "%d", missed_cnt); + if (rc_missed >= missed_cnt_str_sz) { + SWSS_LOG_ERROR("missed cnt (%d) buffer.need=%d given=%d", + missed_cnt, rc_missed, missed_cnt_str_sz); + } + } + else if (rc > 0) { + // timoeut + rc = 0; + } + + return rc; +} + +int event_receive_wrap_1(void *handle) +{ + SWSS_LOG_DEBUG("event_receive_wrap_1 called handle=%p", handle); + return 0; +} + +int event_receive_wrap_2(char *event_str, int sz) +{ + SWSS_LOG_DEBUG("event_receive_wrap_2 called sz=%d", sz); + return 0; +} + +int event_receive_wrap_3(char *event_str, + int event_str_sz, char *missed_cnt, int missed_cnt_sz) +{ + SWSS_LOG_DEBUG("event_receive_wrap_3 called sz=%d, %d", event_str_sz, missed_cnt_sz); + return 0; +} + +int event_receive_wrap_4(void *handle, char *event_str) +{ + SWSS_LOG_DEBUG("event_receive_wrap_4 called handle=%p", handle); + return 0; +} + +int event_receive_wrap_5(const char *event_str) +{ + SWSS_LOG_DEBUG("event_receive_wrap_5 called "); + return 0; +} + diff --git a/common/events.h b/common/events.h index 6a45c754d..98e760230 100644 --- a/common/events.h +++ b/common/events.h @@ -189,7 +189,7 @@ void events_deinit_subscriber(event_handle_t handle); * * return: * 0 - On success - * > 0 - On failure, returns zmq_errno, if failure is zmq socket related. + * > 0 - Implies failure due to timeout. * < 0 - For all other failures * */ @@ -197,7 +197,7 @@ int event_receive(event_handle_t handle, std::string &key, event_params_t ¶ms, int &missed_cnt); /* - * event_receive_wrap + * event_receive_as_struct * * Returns o/p as structured. * This is handy for invocation via python. @@ -219,7 +219,7 @@ typedef struct { int missed_cnt; } event_receive_op_t; -event_receive_op_t event_receive_wrap(event_handle_t handle); +event_receive_op_t event_receive_as_struct(event_handle_t handle); /* Non ZMQ Error codes */ #define ERR_MESSAGE_INVALID -2 diff --git a/common/events_wrap.h b/common/events_wrap.h new file mode 100644 index 000000000..8c106abae --- /dev/null +++ b/common/events_wrap.h @@ -0,0 +1,152 @@ +#ifndef _EVENTS_WRAP_H +#define _EVENTS_WRAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARGS_SOURCE "source" + +/* + * golang has very limited binding to C + * restricting to the i/f to int & pointers + * + * Pass any data as JSON string in & out + */ + +/* + * Init publisher + * + * input: + * args: as JSON string as below + * ' { "source" : " 0 -- Handle to use for subsequent calls. + * < 0 -- Implies failure. Absoulte value is the error code + */ +void * events_init_publisher_wrap(const char *args); + + +/* + * Deinit publisher + * + * input: + * handle -- as provided be events_init_publisher + * + */ +void events_deinit_publisher_wrap(void *handle); + +/* + * Publish an event. + * + * input: + * handle: Handle from init_publisher + * + * args: + * '{ "tag" : "", + * "params": { + * + * } + * }' + * e.g: '{ + * "tag": "bgp-state": + * "params": { + * "timestamp": "2022-08-17T02:39:21.286611Z", + * "ip": "100.126.188.90", + * "status": "down" + * } + * }' + * + * + * Return: + * == 0 -- Published successfully + * < 0 -- Implies failure. Absoulte value is the error code + */ +#define ARGS_TAG "tag" +#define ARGS_PARAMS "params" + +int event_publish_wrap(void *handle, const char *args); + + +/* + * Init subscriber + * + * input: + * args: as JSON string as below + * '{ + * "use_cache" : , + * "recv_timeout": , + * }' + * A missing key will be implied for default. + * e.g: '{ "use_cache": false } + * + * Return: + * > 0 -- Handle to use for subsequent calls. + * < 0 -- Implies failure. Absoulte value is the error code + */ +#define ARGS_USE_CACHE "use_cache" +#define ARGS_RECV_TIMEOUT "recv_timeout" + +void *events_init_subscriber_wrap(const char *args); + + +/* + * Deinit subscribe* input: + * handle -- as provided be events_init_subscriber + * + */ +#define ARGS_KEY "key" +#define ARGS_MISSED_CNT "missed_cnt" + +void events_deinit_subscriber_wrap(void *handle); + +/* + * Receive an event. + * + * input: + * args: + * Buffer for receiving event formatted as below. + * '{ "key" : "", + * "params": { + * + * }, + * "missed_cnt": + * }' + * e.g: '{ + * "key": "sonic-events-bgp:bgp-state": + * "params": { + * "timestamp": "2022-08-17T02:39:21.286611Z", + * "ip": "100.126.188.90", + * "status": "down" + * }, + * "missed_cnt": 0 + * }' + * sz: + * Size of the buffer for receiving event. + * + * + * Return: + * > 0 -- Implies received an event + * = 0 -- implies no event received due to timeout + * < 0 -- Implies failure. Absoulte value is the error code + */ +int event_receive_wrap(void *handle, char *event_str, + int event_str_sz, char *missed_cnt, int missed_cnt_sz); + +int event_receive_wrap_1(void *handle); + +int event_receive_wrap_2(char *event_str, int sz); +int event_receive_wrap_3(char *event_str, + int event_str_sz, char *missed_cnt, int missed_cnt_sz); + +int event_receive_wrap_4(void *handle, char *event_str); + +int event_receive_wrap_5(const char *event_str); + +#ifdef __cplusplus +} +#endif +#endif // _EVENTS_WRAP_H + diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 686b08bc7..bb6866609 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -485,7 +485,7 @@ TEST(events, subscribe) * Events published during subs deinit, which will be provided * to events cache as start up cache. */ - int index_deinit_cache = 0; /* count of events published during subs deinit*/ + int index_deinit_cache = 0; /* index of events published during subs deinit*/ int cnt_deinit_cache = 3; /* count of events published during subs deinit*/ /* From ca8d5b505dbcbce2c587d2a18435f7939a1df178 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 8 Jul 2022 00:00:27 +0000 Subject: [PATCH 32/97] removed hacks; Added set log level API --- common/events.cpp | 37 +++++++++++-------------------------- common/events_wrap.h | 10 +--------- 2 files changed, 12 insertions(+), 35 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index b48dee1c4..b4efe08e8 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -560,11 +560,17 @@ event_receive_wrap(void *handle, char *event_str, } string json_str(res.dump()); rc = snprintf(event_str, event_str_sz, "%s", json_str.c_str()); + if (rc >= event_str_sz) { + SWSS_LOG_ERROR("truncated event buffer.need=%d given=%d", + rc, event_str_sz); + event_str[event_str_sz-1] = 0; + } int rc_missed = snprintf(missed_cnt_str, missed_cnt_str_sz, "%d", missed_cnt); if (rc_missed >= missed_cnt_str_sz) { SWSS_LOG_ERROR("missed cnt (%d) buffer.need=%d given=%d", missed_cnt, rc_missed, missed_cnt_str_sz); + missed_cnt_str[missed_cnt_str_sz-1] = 0; } } else if (rc > 0) { @@ -572,37 +578,16 @@ event_receive_wrap(void *handle, char *event_str, rc = 0; } - return rc; -} - -int event_receive_wrap_1(void *handle) -{ - SWSS_LOG_DEBUG("event_receive_wrap_1 called handle=%p", handle); - return 0; -} + SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s missed=%s\n", + rc, event_str, missed_cnt_str); -int event_receive_wrap_2(char *event_str, int sz) -{ - SWSS_LOG_DEBUG("event_receive_wrap_2 called sz=%d", sz); - return 0; + return rc; } -int event_receive_wrap_3(char *event_str, - int event_str_sz, char *missed_cnt, int missed_cnt_sz) -{ - SWSS_LOG_DEBUG("event_receive_wrap_3 called sz=%d, %d", event_str_sz, missed_cnt_sz); - return 0; -} -int event_receive_wrap_4(void *handle, char *event_str) +void swssSetLogPriority(int pri) { - SWSS_LOG_DEBUG("event_receive_wrap_4 called handle=%p", handle); - return 0; + swss::Logger::setMinPrio((swss::Logger::Priority) pri); } -int event_receive_wrap_5(const char *event_str) -{ - SWSS_LOG_DEBUG("event_receive_wrap_5 called "); - return 0; -} diff --git a/common/events_wrap.h b/common/events_wrap.h index 8c106abae..98eb71384 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -135,15 +135,7 @@ void events_deinit_subscriber_wrap(void *handle); int event_receive_wrap(void *handle, char *event_str, int event_str_sz, char *missed_cnt, int missed_cnt_sz); -int event_receive_wrap_1(void *handle); - -int event_receive_wrap_2(char *event_str, int sz); -int event_receive_wrap_3(char *event_str, - int event_str_sz, char *missed_cnt, int missed_cnt_sz); - -int event_receive_wrap_4(void *handle, char *event_str); - -int event_receive_wrap_5(const char *event_str); +void swssSetLogPriority(int pri); #ifdef __cplusplus } From 0365b3d3af12189fbac802349d96c7f36f529201 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 8 Jul 2022 21:14:48 +0000 Subject: [PATCH 33/97] Minor signature change --- common/events.cpp | 43 +++++++++++++++++++----------------------- common/events.h | 38 ++++++++----------------------------- common/events_common.h | 4 +++- common/events_wrap.h | 28 +++++++++++++++------------ common/logger.cpp | 2 ++ pyext/swsscommon.i | 1 - tests/events_ut.cpp | 17 ++++++++--------- 7 files changed, 56 insertions(+), 77 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index b4efe08e8..ee8159dee 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -419,24 +419,17 @@ events_deinit_subscriber(event_handle_t handle) } - -int -event_receive(event_handle_t handle, string &key, - event_params_t ¶ms, int &missed_cnt) -{ - if ((handle == s_subscriber) && (s_subscriber != NULL)) { - return s_subscriber->event_receive(key, params, missed_cnt); - } - return -1; -} - - event_receive_op_t -event_receive_as_struct(event_handle_t handle) +event_receive(event_handle_t handle) { event_receive_op_t op; - op.rc = event_receive(handle, op.key, op.params, op.missed_cnt); + if ((handle == s_subscriber) && (s_subscriber != NULL)) { + op.rc = s_subscriber->event_receive(op.key, op.params, op.missed_cnt); + } + else { + op.rc = -1; + } return op; } @@ -538,25 +531,24 @@ int event_receive_wrap(void *handle, char *event_str, int event_str_sz, char *missed_cnt_str, int missed_cnt_str_sz) { - string key; - event_params_t params; - int missed_cnt = 0; + event_receive_op_t evt; + int rc = 0; SWSS_LOG_DEBUG("events_receive_wrap h=%p event-sz=%d missed-sz=%d\n", handle, event_str_sz, missed_cnt_str_sz); - int rc = event_receive(handle, key, params, missed_cnt); + evt = event_receive(handle); - if (rc == 0) { + if (evt.rc == 0) { nlohmann::json res = nlohmann::json::object(); { nlohmann::json params_data = nlohmann::json::object(); - for (event_params_t::const_iterator itc = params.begin(); itc != params.end(); ++itc) { + for (event_params_t::const_iterator itc = evt.params.begin(); itc != evt.params.end(); ++itc) { params_data[itc->first] = itc->second; } - res[key] = params_data; + res[evt.key] = params_data; } string json_str(res.dump()); rc = snprintf(event_str, event_str_sz, "%s", json_str.c_str()); @@ -566,17 +558,20 @@ event_receive_wrap(void *handle, char *event_str, event_str[event_str_sz-1] = 0; } - int rc_missed = snprintf(missed_cnt_str, missed_cnt_str_sz, "%d", missed_cnt); + int rc_missed = snprintf(missed_cnt_str, missed_cnt_str_sz, "%d", evt.missed_cnt); if (rc_missed >= missed_cnt_str_sz) { SWSS_LOG_ERROR("missed cnt (%d) buffer.need=%d given=%d", - missed_cnt, rc_missed, missed_cnt_str_sz); + evt.missed_cnt, rc_missed, missed_cnt_str_sz); missed_cnt_str[missed_cnt_str_sz-1] = 0; } } - else if (rc > 0) { + else if (evt.rc > 0) { // timoeut rc = 0; } + else { + rc = evt.rc; + } SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s missed=%s\n", rc, event_str, missed_cnt_str); diff --git a/common/events.h b/common/events.h index 98e760230..dab3289f0 100644 --- a/common/events.h +++ b/common/events.h @@ -151,6 +151,13 @@ event_handle_t events_init_subscriber(bool use_cache=false, void events_deinit_subscriber(event_handle_t handle); +typedef struct { + int rc; /* Return value of event_receive */ + std::string key; /* key */ + event_params_t params; /* Params received */ + int missed_cnt; /* missed count */ +} event_receive_op_t; + /* * Receive an event. * A blocking call unless the subscriber is created with a timeout. @@ -193,36 +200,7 @@ void events_deinit_subscriber(event_handle_t handle); * < 0 - For all other failures * */ -int event_receive(event_handle_t handle, std::string &key, - event_params_t ¶ms, int &missed_cnt); - -/* - * event_receive_as_struct - * - * Returns o/p as structured. - * This is handy for invocation via python. - * - * input: - * handle - As obtained from events_init_subscriber - * - * output: - * None - * - * Return: - * struct that gets return value and all o/p params of event_receive - */ -typedef struct { - int rc; /* Return value of event_receive */ - /* o/p params from event receive */ - std::string key; - event_params_t params; - int missed_cnt; -} event_receive_op_t; - -event_receive_op_t event_receive_as_struct(event_handle_t handle); +event_receive_op_t event_receive(event_handle_t handle); -/* Non ZMQ Error codes */ -#define ERR_MESSAGE_INVALID -2 -#define ERR_OTHER -1 #endif /* !_EVENTS_H */ diff --git a/common/events_common.h b/common/events_common.h index 753c934ee..46c65e767 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -18,11 +18,13 @@ #include #include "logger.h" -#include "events.h" using namespace std; using namespace chrono; +#define ERR_MESSAGE_INVALID -2 +#define ERR_OTHER -1 + /* * Max count of possible concurrent event publishers * We maintain a cache of last seen sequence number per publisher. diff --git a/common/events_wrap.h b/common/events_wrap.h index 98eb71384..ac91f6ca7 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -106,26 +106,27 @@ void events_deinit_subscriber_wrap(void *handle); * Receive an event. * * input: - * args: + * handle - Handle obtained from init subscriber + * event_str: * Buffer for receiving event formatted as below. - * '{ "key" : "", - * "params": { - * - * }, - * "missed_cnt": - * }' + * : { + * + * } * e.g: '{ - * "key": "sonic-events-bgp:bgp-state": - * "params": { + * "sonic-events-bgp:bgp-state": { * "timestamp": "2022-08-17T02:39:21.286611Z", * "ip": "100.126.188.90", * "status": "down" - * }, - * "missed_cnt": 0 + * } * }' - * sz: + * event_str_sz: * Size of the buffer for receiving event. * + * missed_cnt: + * Buffer to receive missed count as int converted to string. + * + * missed_cnt_sz: + * Size of the missed_cnt buffer. * * Return: * > 0 -- Implies received an event @@ -135,6 +136,9 @@ void events_deinit_subscriber_wrap(void *handle); int event_receive_wrap(void *handle, char *event_str, int event_str_sz, char *missed_cnt, int missed_cnt_sz); +/* + * Set SWSS log priority + */ void swssSetLogPriority(int pri); #ifdef __cplusplus diff --git a/common/logger.cpp b/common/logger.cpp index b27cbed93..2c098eead 100644 --- a/common/logger.cpp +++ b/common/logger.cpp @@ -186,6 +186,8 @@ Logger& Logger::getInstance() void Logger::setMinPrio(Priority prio) { getInstance().m_minPrio = prio; + SWSS_LOG_ERROR("loglevel Set=%d", prio); + } Logger::Priority Logger::getMinPrio() diff --git a/pyext/swsscommon.i b/pyext/swsscommon.i index fbedc634c..34d2a63e8 100644 --- a/pyext/swsscommon.i +++ b/pyext/swsscommon.i @@ -218,6 +218,5 @@ T castSelectableObj(swss::Selectable *temp) %include "dbinterface.h" %include "logger.h" %include "events.h" -%ignore event_receive(event_handle_t, std::string &, event_params_t &, int &); %include "status_code_util.h" diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index bb6866609..f370e0db3 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -540,24 +540,23 @@ TEST(events, subscribe) pub_events(index_subs, cnt_subs); for(i=0; true; ++i) { - string key, exp_key; - event_params_t params; - int missed = -1; + string exp_key; + event_receive_op_t evt; - int rc = event_receive(hsub, key, params, missed); + evt = event_receive(hsub); - if (rc != 0) { - EXPECT_EQ(EAGAIN, rc); + if (evt.rc != 0) { + EXPECT_EQ(EAGAIN, evt.rc); break; } - EXPECT_EQ(ldata[i].params, params); + EXPECT_EQ(ldata[i].params, evt.params); exp_key = ldata[i].source + ":" + ldata[i].tag; - EXPECT_EQ(exp_key, key); + EXPECT_EQ(exp_key, evt.key); - EXPECT_EQ(ldata[i].missed_cnt, missed); + EXPECT_EQ(ldata[i].missed_cnt, evt.missed_cnt); } EXPECT_EQ(i, (int)ARRAY_SIZE(ldata)); From daf2ceda2af39c7346e201615a752f2d15508542 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Mon, 11 Jul 2022 23:15:34 +0000 Subject: [PATCH 34/97] Added unit test for C wrap --- tests/events_ut.cpp | 139 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 125 insertions(+), 14 deletions(-) diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index f370e0db3..697f33941 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -5,9 +5,11 @@ #include #include #include +#include "common/json.hpp" #include "gtest/gtest.h" #include "common/events_common.h" #include "common/events.h" +#include "common/events_wrap.h" #include "common/events_pi.h" using namespace std; @@ -102,7 +104,7 @@ void run_sub() read_source.swap(source); } } - + terminate_sub = false; zmq_close(mock_sub); } @@ -161,7 +163,7 @@ parse_read_evt(string &source, internal_event_t &evt, return ret; } -TEST(events, publish) +void do_test_publish(bool wrap) { { /* Direct log messages to stdout */ @@ -177,6 +179,7 @@ TEST(events, publish) event_params_t params0({{"ip", "10.10.10.10"}, {"state", "up"}}); event_params_t params1; event_params_t::iterator it_param; + event_handle_t h; string rid0, rid1; sequence_t seq0, seq1 = 0; @@ -189,13 +192,41 @@ TEST(events, publish) thread thr(&pub_serve_commands); thread thr_sub(&run_sub); - event_handle_t h = events_init_publisher(evt_source0); + if (wrap) { + string json_str; + nlohmann::json obj = nlohmann::json::object(); + + obj[ARGS_SOURCE] = evt_source0; + + json_str = obj.dump(); + h = events_init_publisher_wrap(json_str.c_str()); + } + else { + h = events_init_publisher(evt_source0); + } EXPECT_TRUE(NULL != h); /* Take a pause to allow publish to connect async */ this_thread::sleep_for(chrono::milliseconds(300)); - EXPECT_EQ(0, event_publish(h, evt_tag0, ¶ms0)); + if (wrap) { + string json_str; + nlohmann::json obj = nlohmann::json::object(); + nlohmann::json obj_params = nlohmann::json::object(); + + for (it_param = params0.begin(); it_param != params0.end(); ++it_param) { + obj_params[it_param->first] = it_param->second; + } + obj[ARGS_PARAMS] = obj_params; + obj[ARGS_TAG] = evt_tag0; + + json_str = obj.dump(); + + EXPECT_EQ(0, event_publish_wrap(h, json_str.c_str())); + } + else { + EXPECT_EQ(0, event_publish(h, evt_tag0, ¶ms0)); + } parse_read_evt(read_source, read_evt, rid0, seq0, rd_key0, rd_params0); @@ -266,12 +297,22 @@ TEST(events, publish) thr.join(); thr_sub.join(); - events_deinit_publisher(h); + events_deinit_publisher_wrap(h); events_deinit_publisher(h1); zmq_ctx_term(zmq_ctx); zmq_ctx = NULL; - printf("************ PUBLISH DONE ***************\n"); + printf("************ PUBLISH wrap=%d DONE ***************\n", wrap); +} + +TEST(events, publish) +{ + do_test_publish(false); +} + +TEST(events, publish_wrap) +{ + do_test_publish(true); } typedef struct { @@ -448,7 +489,7 @@ void run_pub() pub_send_cnt = 0; } zmq_close(mock_pub); - + pub_send_cnt = 0; } @@ -469,7 +510,7 @@ void pub_events(int index, int cnt) } -TEST(events, subscribe) +void do_test_subscribe(bool wrap) { int i; #if 0 @@ -511,14 +552,28 @@ TEST(events, subscribe) thread thr_svc(&pub_serve_commands); thread thr_pub(&run_pub); - hsub = events_init_subscriber(true); + if (wrap) { + nlohmann::json obj = nlohmann::json::object(); + + obj[ARGS_USE_CACHE] = true; + + string jstr(obj.dump()); + hsub = events_init_subscriber_wrap(jstr.c_str()); + } + else { + hsub = events_init_subscriber(true); + } EXPECT_TRUE(NULL != hsub); EXPECT_EQ(last_svc_code, EVENT_CACHE_STOP); /* Publish messages for deinit to capture */ pub_events(index_deinit_cache, cnt_deinit_cache); - events_deinit_subscriber(hsub); + if (wrap) { + events_deinit_subscriber_wrap(hsub); + } else { + events_deinit_subscriber(hsub); + } EXPECT_EQ(last_svc_code, EVENT_CACHE_START); EXPECT_TRUE(cnt_deinit_cache == (int)lst_cache.size()); @@ -533,7 +588,17 @@ TEST(events, subscribe) EXPECT_EQ((int)lst_cache.size(), index_subs+overlap_subs); /* We publish all events ahead of receive, so set a timeout */ - hsub = events_init_subscriber(true, 100); + if (wrap) { + nlohmann::json obj = nlohmann::json::object(); + + obj[ARGS_USE_CACHE] = true; + obj[ARGS_RECV_TIMEOUT] = 100; + string jstr(obj.dump()); + hsub = events_init_subscriber_wrap(jstr.c_str()); + } + else { + hsub = events_init_subscriber(true, 100); + } EXPECT_TRUE(NULL != hsub); EXPECT_EQ(last_svc_code, EVENT_CACHE_STOP); @@ -543,7 +608,37 @@ TEST(events, subscribe) string exp_key; event_receive_op_t evt; - evt = event_receive(hsub); + if (wrap) { + char event_str[1024]; + char missed_cnt[100]; + + int rc = event_receive_wrap(hsub, event_str, sizeof(event_str), + missed_cnt, sizeof(missed_cnt)); + + if (rc != 0) { + const auto &data = nlohmann::json::parse(event_str); + EXPECT_EQ(1, data.size()); + + auto it = data.cbegin(); + + evt.key = it.key(); + auto val = it.value(); + for (auto itp = val.begin(); itp != val.end(); ++itp) { + evt.params[itp.key()] = itp.value(); + } + evt.rc = 0; + evt.missed_cnt = stoi(string(missed_cnt)); + } + else if (rc == 0) { + evt.rc = EAGAIN; + } + else { + evt.rc = rc; + } + } + else { + evt = event_receive(hsub); + } if (evt.rc != 0) { EXPECT_EQ(EAGAIN, evt.rc); @@ -561,7 +656,11 @@ TEST(events, subscribe) EXPECT_EQ(i, (int)ARRAY_SIZE(ldata)); - events_deinit_subscriber(hsub); + if (wrap) { + events_deinit_subscriber_wrap(hsub); + } else { + events_deinit_subscriber(hsub); + } /* Don't need event's service anymore */ terminate_svc = true; @@ -570,6 +669,18 @@ TEST(events, subscribe) thr_svc.join(); thr_pub.join(); zmq_ctx_term(zmq_ctx); - printf("************ SUBSCRIBE DONE ***************\n"); + printf("************ SUBSCRIBE wrap=%d DONE ***************\n", wrap); +} + +TEST(events, subscribe) +{ + do_test_subscribe(false); } + +TEST(events, subscribe_wrap) +{ + do_test_subscribe(true); +} + + From 8c42e85caeb714139adca6cebb18768b2a9cdd58 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 12 Jul 2022 22:53:43 +0000 Subject: [PATCH 35/97] Corrected per review comments; Addede log message for published events --- common/events.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index ee8159dee..b7732172c 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -74,6 +74,7 @@ EventPublisher::publish(const string tag, const event_params_t *params) { int rc; internal_event_t event_data; + string key(m_event_source + ":" + tag); if (m_event_service.is_active()) { string s; @@ -108,7 +109,7 @@ EventPublisher::publish(const string tag, const event_params_t *params) map_to_str(*params).c_str()); { - map_str_str_t event_str_map = { { m_event_source + ":" + tag, param_str}}; + map_str_str_t event_str_map = { { key, param_str}}; rc = serialize(event_str_map, event_data[EVENT_STR_DATA]); RET_ON_ERR(rc == 0, "failed to serialize event str %s", @@ -120,6 +121,22 @@ EventPublisher::publish(const string tag, const event_params_t *params) rc = zmq_message_send(m_socket, m_event_source, event_data); RET_ON_ERR(rc == 0, "failed to send for tag %s", tag.c_str()); + + { + nlohmann::json msg = nlohmann::json::object(); + { + nlohmann::json params_data = nlohmann::json::object(); + + for (event_params_t::const_iterator itc = params->begin(); + itc != params->end(); ++itc) { + params_data[itc->first] = itc->second; + } + msg[key] = params_data; + } + string json_str(msg.dump()); + SWSS_LOG_INFO("EVENT_PUBLISHED: %s", json_str.c_str()); + } + out: return rc; } @@ -512,9 +529,9 @@ events_init_subscriber_wrap(const char *args) } } } - void *h = events_init_subscriber(use_cache, recv_timeout); - SWSS_LOG_DEBUG("events_init_subscriber_wrap: handle=%p", h); - return h; + void *handle = events_init_subscriber(use_cache, recv_timeout); + SWSS_LOG_DEBUG("events_init_subscriber_wrap: handle=%p", handle); + return handle; } @@ -534,7 +551,7 @@ event_receive_wrap(void *handle, char *event_str, event_receive_op_t evt; int rc = 0; - SWSS_LOG_DEBUG("events_receive_wrap h=%p event-sz=%d missed-sz=%d\n", + SWSS_LOG_DEBUG("events_receive_wrap handle=%p event-sz=%d missed-sz=%d\n", handle, event_str_sz, missed_cnt_str_sz); evt = event_receive(handle); @@ -566,7 +583,7 @@ event_receive_wrap(void *handle, char *event_str, } } else if (evt.rc > 0) { - // timoeut + // timeout rc = 0; } else { From cf30d4b82dbe748d314e3b02d784c4a570301a2f Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 15 Jul 2022 17:45:45 +0000 Subject: [PATCH 36/97] minor updates;no logical code changes --- common/events.cpp | 24 +++++++++++++++--------- common/events_common.h | 12 +++++++++++- common/events_service.cpp | 8 ++++++++ common/logger.cpp | 2 -- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index b7732172c..4d6449b77 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -145,10 +145,10 @@ event_handle_t events_init_publisher(const string event_source) { event_handle_t ret = NULL; - lst_publishers_t::iterator it = s_publishers.find(event_source); - if (it != s_publishers.end()) { + lst_publishers_t::const_iterator itc = s_publishers.find(event_source); + if (itc != s_publishers.end()) { // Pre-exists - ret = it->second; + ret = itc->second; } else { EventPublisher *p = new EventPublisher(); @@ -366,17 +366,15 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ /* Find any missed events for this runtime ID */ missed_cnt = 0; sequence_t seq = str_to_seq(event_data[EVENT_SEQUENCE]); - track_info_t::iterator it = m_track.find(event_data[EVENT_RUNTIME_ID]); - if (it != m_track.end()) { + track_info_t::const_iterator itc = m_track.find(event_data[EVENT_RUNTIME_ID]); + if (itc != m_track.end()) { /* current seq - last read - 1 == 0 if none missed */ - missed_cnt = seq - it->second.seq - 1; - it->second = evt_info_t(seq); + missed_cnt = seq - itc->second.seq - 1; } else { if (m_track.size() > (MAX_PUBLISHERS_COUNT + 10)) { prune_track(); } - m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); } if (missed_cnt >= 0) { map_str_str_t ev; @@ -394,6 +392,8 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ rc = deserialize(ev.begin()->second, params); RET_ON_ERR(rc == 0, "failed to deserialize params %s", ev.begin()->second.substr(0, 32).c_str()); + + m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); } else { @@ -413,15 +413,21 @@ event_handle_t events_init_subscriber(bool use_cache, int recv_timeout, const event_subscribe_sources_t *sources) { + EventSubscriber *sub = NULL; + if (s_subscriber == NULL) { - EventSubscriber *sub = new EventSubscriber(); + sub = new EventSubscriber(); RET_ON_ERR(sub->init(use_cache, recv_timeout, sources) == 0, "Failed to init subscriber"); s_subscriber = sub; + sub = NULL; } out: + if (sub != NULL) { + delete sub; + } return s_subscriber; } diff --git a/common/events_common.h b/common/events_common.h index 46c65e767..b6c2713d5 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -29,7 +29,17 @@ using namespace chrono; * Max count of possible concurrent event publishers * We maintain a cache of last seen sequence number per publisher. * This provides a MAX ceiling for cache. - * Any more publishers over this count should indicate a serious bug. + * A publisher exiting will be not known to receiver, so some publishers + * who gets periodically invoked as every N seconds, could over time + * cause the cache over flow. + * whenever the cache hits this max, old instances are removed. + * + * RFE: Publishers who publish at least 1 event, declare their + * exit via a reserved event, so receivers could drop tracking + * hence avoid overflow. Else, a long running process with no event + * but still active could lose its record. This is still not very + * serious, as first message from such publisher is less likely + * to be lost and it could create a record. */ #define MAX_PUBLISHERS_COUNT 1000 diff --git a/common/events_service.cpp b/common/events_service.cpp index 8b86eba79..4c14e4d5d 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -44,7 +44,11 @@ event_service::init_client(void *zmq_ctx, int block_ms) RET_ON_ERR(rc == 0, "Failed to ZMQ_RCVTIMEO to %d", block_ms); m_socket = sock; + sock = NULL; out: + if (sock != NULL) { + zmq_close(sock); + } return rc; } @@ -65,7 +69,11 @@ event_service::init_server(void *zmq_ctx, int block_ms) RET_ON_ERR(rc == 0, "Failed to ZMQ_RCVTIMEO to %d", block_ms); m_socket = sock; + sock = NULL; out: + if (sock != NULL) { + zmq_close(sock); + } return rc; } diff --git a/common/logger.cpp b/common/logger.cpp index 2c098eead..b27cbed93 100644 --- a/common/logger.cpp +++ b/common/logger.cpp @@ -186,8 +186,6 @@ Logger& Logger::getInstance() void Logger::setMinPrio(Priority prio) { getInstance().m_minPrio = prio; - SWSS_LOG_ERROR("loglevel Set=%d", prio); - } Logger::Priority Logger::getMinPrio() From b5879634cff4a86d5692269ba7578dc333d58874 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Mon, 18 Jul 2022 23:42:45 +0000 Subject: [PATCH 37/97] corrected per review comments; Added accidentally removed test --- tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index f3cf2886c..e9e2c2a96 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -37,6 +37,7 @@ tests_SOURCES = redis_ut.cpp \ saiaclschema_ut.cpp \ countertable_ut.cpp \ timer_ut.cpp \ + cli_ut.cpp \ events_common_ut.cpp \ events_service_ut.cpp \ events_ut.cpp \ From 6bebad35f89bffb4589aebdd0ed6189f7d019251 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Mon, 18 Jul 2022 23:47:28 +0000 Subject: [PATCH 38/97] Added back accidentally removed test code file --- tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index f3cf2886c..e9e2c2a96 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -37,6 +37,7 @@ tests_SOURCES = redis_ut.cpp \ saiaclschema_ut.cpp \ countertable_ut.cpp \ timer_ut.cpp \ + cli_ut.cpp \ events_common_ut.cpp \ events_service_ut.cpp \ events_ut.cpp \ From 94d9c236223d03f9e41858dc0eb0b4334be5059e Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 19 Jul 2022 00:13:33 +0000 Subject: [PATCH 39/97] retire runtime id on deinit --- common/events.cpp | 126 ++++++++++++++++++++++++++++------------- common/events_common.h | 36 ++++++++---- common/events_pi.h | 1 + 3 files changed, 114 insertions(+), 49 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 4d6449b77..c0c398078 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -43,14 +43,6 @@ int EventPublisher::init(const string event_source) m_event_source = event_source; - { - uuid_t id; - char uuid_str[UUID_STR_SIZE]; - uuid_generate(id); - uuid_unparse(id, uuid_str); - m_runtime_id = string(uuid_str); - } - m_socket = sock; out: if (m_socket == NULL) { @@ -61,6 +53,10 @@ int EventPublisher::init(const string event_source) EventPublisher::~EventPublisher() { + if (!m_runtime_id.empty()) { + /* Retire the runtime ID */ + send_evt(EVENT_STR_CTRL_DEINIT); + } m_event_service.close_service(); if (m_socket != NULL) { zmq_close(m_socket); @@ -69,12 +65,31 @@ EventPublisher::~EventPublisher() } +int +EventPublisher::send_evt(const string str_data) +{ + internal_event_t event_data; + int rc; + + event_data[EVENT_STR_DATA] = str_data; + event_data[EVENT_RUNTIME_ID] = m_runtime_id; + /* A value of 0 will indicate rollover */ + ++m_sequence; + event_data[EVENT_SEQUENCE] = seq_to_str(m_sequence); + + rc = zmq_message_send(m_socket, m_event_source, event_data); + RET_ON_ERR(rc == 0, "failed to send for tag %s", tag.c_str()); +out: + return rc; +} + + int EventPublisher::publish(const string tag, const event_params_t *params) { int rc; - internal_event_t event_data; string key(m_event_source + ":" + tag); + string str_data; if (m_event_service.is_active()) { string s; @@ -89,6 +104,15 @@ EventPublisher::publish(const string tag, const event_params_t *params) m_event_service.close_service(); } + if (m_runtime_id.empty()) { + uuid_t id; + char uuid_str[UUID_STR_SIZE]; + uuid_generate(id); + uuid_unparse(id, uuid_str); + m_runtime_id = string(uuid_str); + } + + /* Check for timestamp in params. If not, provide it. */ string param_str; event_params_t evt_params; @@ -111,16 +135,12 @@ EventPublisher::publish(const string tag, const event_params_t *params) { map_str_str_t event_str_map = { { key, param_str}}; - rc = serialize(event_str_map, event_data[EVENT_STR_DATA]); + rc = serialize(event_str_map, str_data); RET_ON_ERR(rc == 0, "failed to serialize event str %s", map_to_str(event_str_map).c_str()); } - event_data[EVENT_RUNTIME_ID] = m_runtime_id; - ++m_sequence; - event_data[EVENT_SEQUENCE] = seq_to_str(m_sequence); - rc = zmq_message_send(m_socket, m_event_source, event_data); - RET_ON_ERR(rc == 0, "failed to send for tag %s", tag.c_str()); + rc = send_evt(str_data); { nlohmann::json msg = nlohmann::json::object(); @@ -339,6 +359,7 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ int rc = 0; key.clear(); event_params_t().swap(params); + missed_cnt = 0; while (key.empty()) { internal_event_t event_data; @@ -364,40 +385,67 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ } /* Find any missed events for this runtime ID */ - missed_cnt = 0; + int this_missed_cnt = 0; sequence_t seq = str_to_seq(event_data[EVENT_SEQUENCE]); track_info_t::const_iterator itc = m_track.find(event_data[EVENT_RUNTIME_ID]); if (itc != m_track.end()) { /* current seq - last read - 1 == 0 if none missed */ - missed_cnt = seq - itc->second.seq - 1; + if (seq != 0) { + this_missed_cnt = seq - itc->second.seq - 1; + } + else { + /* handle rollover */ + this_missed_cnt = SEQUENCE_MAX - itc->second.seq; + } } else { + /* + * First message seen from this runtime id, implying + * all earlier messages are lost. + */ + if (seq != 0) { + this_missed_cnt = seq - 1; + } + /* roll over is nearly impossible - 4GB events not seen */ + + /* May need to add new ID to track; Prune if needed */ if (m_track.size() > (MAX_PUBLISHERS_COUNT + 10)) { prune_track(); } } - if (missed_cnt >= 0) { - map_str_str_t ev; - - rc = deserialize(event_data[EVENT_STR_DATA], ev); - RET_ON_ERR(rc == 0, "Failed to deserialize %s", - event_data[EVENT_STR_DATA].substr(0, 32).c_str()); - - if (ev.size() != 1) rc = -1; - RET_ON_ERR(rc == 0, "Expect string (%s) deserialize to one key", - event_data[EVENT_STR_DATA].substr(0, 32).c_str()); - - key = ev.begin()->first; - - rc = deserialize(ev.begin()->second, params); - RET_ON_ERR(rc == 0, "failed to deserialize params %s", - ev.begin()->second.substr(0, 32).c_str()); - - m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); - - } - else { - /* negative value implies duplicate; Possibly seen from cache */ + missed_cnt += this_missed_cnt; + + if (event_data[EVENT_STR_DATA].compare(0, EVENT_STR_CTRL_PREFIX_SZ, + EVENT_STR_CTRL_PREFIX) != 0) { + if (this_missed_cnt >= 0) { + map_str_str_t ev; + + rc = deserialize(event_data[EVENT_STR_DATA], ev); + RET_ON_ERR(rc == 0, "Failed to deserialize %s", + event_data[EVENT_STR_DATA].substr(0, 32).c_str()); + + if (ev.size() != 1) rc = -1; + RET_ON_ERR(rc == 0, "Expect string (%s) deserialize to one key", + event_data[EVENT_STR_DATA].substr(0, 32).c_str()); + + key = ev.begin()->first; + + rc = deserialize(ev.begin()->second, params); + RET_ON_ERR(rc == 0, "failed to deserialize params %s", + ev.begin()->second.substr(0, 32).c_str()); + + m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); + } + else { + /* negative value implies duplicate; Possibly seen from cache */ + } + } else { + /* This is control message */ + if (event_data[EVENT_STR_DATA] == EVENT_STR_CTRL_DEINIT) { + if (itc != m_track.end()) { + m_track.erase(event_data[EVENT_RUNTIME_ID]); + } + } } } out: diff --git a/common/events_common.h b/common/events_common.h index b6c2713d5..877cbddb1 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -1,3 +1,5 @@ + +/* The internal code that caches runtime-IDs could retire upon de-init */ #ifndef _EVENTS_COMMON_H #define _EVENTS_COMMON_H /* @@ -25,21 +27,22 @@ using namespace chrono; #define ERR_MESSAGE_INVALID -2 #define ERR_OTHER -1 +#define UINT32_MAX ((uint32_t)-1) + /* * Max count of possible concurrent event publishers * We maintain a cache of last seen sequence number per publisher. * This provides a MAX ceiling for cache. - * A publisher exiting will be not known to receiver, so some publishers - * who gets periodically invoked as every N seconds, could over time - * cause the cache over flow. - * whenever the cache hits this max, old instances are removed. + * An exiting publisher retires its runtime-ID explicitly. + * A crashed publisher or event lost for any reason will leave + * behind the runtime ID. Overtime, these leaked IDs could fill the cache. + * Hence whenever the cache hits this max, old instances are removed. + * old instances are identified using time of last publish. * - * RFE: Publishers who publish at least 1 event, declare their - * exit via a reserved event, so receivers could drop tracking - * hence avoid overflow. Else, a long running process with no event - * but still active could lose its record. This is still not very - * serious, as first message from such publisher is less likely - * to be lost and it could create a record. + * In the scenario of too many publisher crashed and an instance that + * that does not publish for a very long time, could get purged. + * But crashing publishers is a bigger issue and we need not be + * perfect in that scenario. */ #define MAX_PUBLISHERS_COUNT 1000 @@ -187,6 +190,8 @@ typedef map internal_event_t; /* Sequence is converted to string in message */ typedef uint32_t sequence_t; +#define SEQUENCE_MAX UINT32_MAX + typedef string runtime_id_t; /* @@ -196,6 +201,17 @@ typedef string runtime_id_t; * { EVENT_SEQUENCE, "" } }; */ +/* + * Control messages could be sent as events with specific + * prefix "CONTROL_" + * e.g. CONTROL_DEINIT + */ +#define EVENT_STR_CTRL_PREFIX "CONTROL_" +#define EVENT_STR_CTRL_PREFIX_SZ ((int)sizeof(EVENT_STR_CTRL_PREFIX) - 1) + +/* The internal code that caches runtime-IDs could retire upon de-init */ +#define EVENT_STR_CTRL_DEINIT "CONTROL_DEINIT" + typedef vector internal_events_lst_t; /* Cache maintains the part 2 of an event as serialized string. */ diff --git a/common/events_pi.h b/common/events_pi.h index 46552654b..26172eaef 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -48,6 +48,7 @@ class EventPublisher : public events_base int publish(const string event_tag, const event_params_t *params); private: + int send_evt(const string str_data); void *m_zmq_ctx; void *m_socket; From aa45b1bbf8876da4f85dcec0797c3c8bc0aa2968 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 19 Jul 2022 00:20:28 +0000 Subject: [PATCH 40/97] restore accidental removal --- tests/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index e9e2c2a96..d53f88995 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -45,4 +45,4 @@ tests_SOURCES = redis_ut.cpp \ tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS) -tests_LDADD = $(LDADD_GTEST) -lpthread -L$(top_srcdir)/common -lswsscommon $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -luuid -lboost_serialization +tests_LDADD = $(LDADD_GTEST) -lpthread -L$(top_srcdir)/common -lswsscommon $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -L$(top_srcdir)/sonic-db-cli -lsonicdbcli -lzmq -luuid -lboost_serialization From 5e1e28101b774fa75b6b6382ae6df03181153330 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 21 Jul 2022 00:11:51 +0000 Subject: [PATCH 41/97] Switched to shared_ptr per review comments --- common/events.cpp | 141 +++++++++++++++++++++++++-------------------- common/events_pi.h | 27 +++++++-- 2 files changed, 103 insertions(+), 65 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 4d6449b77..941af34cc 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -7,14 +7,58 @@ * duplicates helps reduce load. */ -typedef map lst_publishers_t; -lst_publishers_t s_publishers; +lst_publishers_t EventPublisher::s_publishers; + +event_handle_t +EventPublisher::get_publisher(const string event_source) +{ + event_handle_t ret = NULL; + lst_publishers_t::const_iterator itc = s_publishers.find(event_source); + if (itc != s_publishers.end()) { + // Pre-exists + ret = itc->second; + } + else { + EventPublisher_ptr_t p(n.get()ew EventPublisher()); + + int rc = p->init(event_source); + + if (rc == 0) { + ret = p.get(); + s_publishers[event_source] = p; + } + } + return ret; +} + +void +EventPublisher::drop_publisher(event_handle_t handle) +{ + lst_publishers_t::iterator it; + + for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { + if (it->second.get() == handle) { + s_publishers.erase(it); + break; + } + } +} EventPublisher::EventPublisher() : m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0) { } +static string +get_uuid() +{ + uuid_t id; + char uuid_str[UUID_STR_SIZE]; + uuid_generate(id); + uuid_unparse(id, uuid_str); + return string(uuid_str); +} + int EventPublisher::init(const string event_source) { m_zmq_ctx = zmq_ctx_new(); @@ -43,13 +87,7 @@ int EventPublisher::init(const string event_source) m_event_source = event_source; - { - uuid_t id; - char uuid_str[UUID_STR_SIZE]; - uuid_generate(id); - uuid_unparse(id, uuid_str); - m_runtime_id = string(uuid_str); - } + m_runtime_id = get_uuid(); m_socket = sock; out: @@ -144,40 +182,13 @@ EventPublisher::publish(const string tag, const event_params_t *params) event_handle_t events_init_publisher(const string event_source) { - event_handle_t ret = NULL; - lst_publishers_t::const_iterator itc = s_publishers.find(event_source); - if (itc != s_publishers.end()) { - // Pre-exists - ret = itc->second; - } - else { - EventPublisher *p = new EventPublisher(); - - int rc = p->init(event_source); - - if (rc != 0) { - delete p; - } - else { - ret = p; - s_publishers[event_source] = p; - } - } - return ret; + return EventPublisher::get_publisher(event_source); } void events_deinit_publisher(event_handle_t handle) { - lst_publishers_t::iterator it; - - for(it=s_publishers.begin(); it != s_publishers.end(); ++it) { - if (it->second == handle) { - delete it->second; - s_publishers.erase(it); - break; - } - } + EventPublisher::drop_publisher(handle); } int @@ -193,6 +204,34 @@ event_publish(event_handle_t handle, const string tag, const event_params_t *par } +event_handle_t +EventSubscriber::get_subscriber(bool use_cache, int recv_timeout, + const event_subscribe_sources_t *sources) +{ + + if (s_subscriber == NULL) { + EventSubscriber_ptr_t sub(new EventSubscriber()); + + RET_ON_ERR(sub->init(use_cache, recv_timeout, sources) == 0, + "Failed to init subscriber"); + + s_subscriber = sub; + } +out: + return s_subscriber.get(); +} + + +void +EventSubscriber::drop_subscriber(event_handle_t handle) +{ + if ((handle == s_subscriber) && (s_subscriber != NULL)) { + delete s_subscriber; + s_subscriber = NULL; + } +} + + EventSubscriber::EventSubscriber() : m_zmq_ctx(NULL), m_socket(NULL), m_cache_read(false) {}; @@ -407,41 +446,21 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ /* Expect only one subscriber per process */ -static EventSubscriber *s_subscriber = NULL; +EventSubscriber *EventSubscriber::s_subscriber = NULL; event_handle_t events_init_subscriber(bool use_cache, int recv_timeout, const event_subscribe_sources_t *sources) { - EventSubscriber *sub = NULL; - - if (s_subscriber == NULL) { - sub = new EventSubscriber(); - - RET_ON_ERR(sub->init(use_cache, recv_timeout, sources) == 0, - "Failed to init subscriber"); - - s_subscriber = sub; - sub = NULL; - } -out: - if (sub != NULL) { - delete sub; - } - return s_subscriber; + return EventSubscriber::get_subscriber(use_cache, recv_timeout, sources); } - void events_deinit_subscriber(event_handle_t handle) { - if ((handle == s_subscriber) && (s_subscriber != NULL)) { - delete s_subscriber; - s_subscriber = NULL; - } + EventSubscriber::drop_subscriber(handle); } - event_receive_op_t event_receive(event_handle_t handle) { diff --git a/common/events_pi.h b/common/events_pi.h index 46552654b..4258cb57c 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -35,19 +35,29 @@ class events_base * There can be multiple sender processes/threads for a single source. * */ +class EventPublisher; +typedef shared_ptr EventPublisher_ptr_t; +typedef map lst_publishers_t; + class EventPublisher : public events_base { - public: - EventPublisher(); + static lst_publishers_t s_publishers; + public: virtual ~EventPublisher(); int init(const string event_source); int publish(const string event_tag, const event_params_t *params); + + static event_handle_t get_publisher(const string event_source); + static void drop_publisher((event_handle_t handle); + private: + EventPublisher(); + void *m_zmq_ctx; void *m_socket; @@ -72,12 +82,14 @@ class EventPublisher : public events_base * would have nearly no impact on others. * */ +class EventSubscriber; +typedef shared_ptr EventSubscriber_ptr_t; class EventSubscriber : public events_base { + static EventSubscriber_ptr_t s_subscriber; + public: - EventSubscriber(); - int init(bool use_cache=false, int recv_timeout= -1, const event_subscribe_sources_t *subs_sources=NULL); @@ -86,7 +98,14 @@ class EventSubscriber : public events_base int event_receive(string &key, event_params_t ¶ms, int &missed_cnt); + static event_handle_t get_subscriber(bool use_cache, int recv_timeout, + const event_subscribe_sources_t *sources); + + static void drop_subscriber(event_handle_t handle); + private: + EventSubscriber(); + void *m_zmq_ctx; void *m_socket; From 7bbce0a1d973be36971498f66b2fc95c45ff29ff Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 21 Jul 2022 01:59:36 +0000 Subject: [PATCH 42/97] minor non logical code changes --- common/events.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 941af34cc..96af60dc9 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -44,10 +44,8 @@ EventPublisher::drop_publisher(event_handle_t handle) } } -EventPublisher::EventPublisher() : - m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0) -{ -} +EventPublisher::EventPublisher(): m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0) +{} static string get_uuid() @@ -232,7 +230,7 @@ EventSubscriber::drop_subscriber(event_handle_t handle) } -EventSubscriber::EventSubscriber() : m_zmq_ctx(NULL), m_socket(NULL), +EventSubscriber::EventSubscriber(): m_zmq_ctx(NULL), m_socket(NULL), m_cache_read(false) {}; From a0587a0f75cd59b084ef70a7bf8d2ff9f5c48406 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 21 Jul 2022 16:52:30 +0000 Subject: [PATCH 43/97] fix syntax --- common/events.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/events.cpp b/common/events.cpp index 96af60dc9..47b5a60cc 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -19,7 +19,7 @@ EventPublisher::get_publisher(const string event_source) ret = itc->second; } else { - EventPublisher_ptr_t p(n.get()ew EventPublisher()); + EventPublisher_ptr_t p(new EventPublisher()); int rc = p->init(event_source); From 3169a4d353fe739947639cc1a20036f74a1656c5 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 21 Jul 2022 18:04:26 +0000 Subject: [PATCH 44/97] few follow up changes for bare ptr to shared ptr conversion --- common/events.cpp | 59 +++++++++++++++++++++++++++------------------- common/events_pi.h | 30 +++++++++++++---------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 47b5a60cc..9f3ebb482 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -16,7 +16,7 @@ EventPublisher::get_publisher(const string event_source) lst_publishers_t::const_iterator itc = s_publishers.find(event_source); if (itc != s_publishers.end()) { // Pre-exists - ret = itc->second; + ret = itc->second.get(); } else { EventPublisher_ptr_t p(new EventPublisher()); @@ -44,6 +44,19 @@ EventPublisher::drop_publisher(event_handle_t handle) } } +int +EventPublisher::do_publish(event_handle_t handle, const string tag, const event_params_t *params) +{ + lst_publishers_t::const_iterator itc; + for(itc=s_publishers.begin(); itc != s_publishers.end(); ++itc) { + if (itc->second.get() == handle) { + return itc->second->publish(tag, params); + } + } + return -1; +} + + EventPublisher::EventPublisher(): m_zmq_ctx(NULL), m_socket(NULL), m_sequence(0) {} @@ -192,16 +205,13 @@ events_deinit_publisher(event_handle_t handle) int event_publish(event_handle_t handle, const string tag, const event_params_t *params) { - lst_publishers_t::const_iterator itc; - for(itc=s_publishers.begin(); itc != s_publishers.end(); ++itc) { - if (itc->second == handle) { - return itc->second->publish(tag, params); - } - } - return -1; + return EventPublisher::do_publish(handle, tag, params); } +/* Expect only one subscriber per process */ +EventSubscriber_ptr_t EventSubscriber::s_subscriber; + event_handle_t EventSubscriber::get_subscriber(bool use_cache, int recv_timeout, const event_subscribe_sources_t *sources) @@ -223,13 +233,26 @@ EventSubscriber::get_subscriber(bool use_cache, int recv_timeout, void EventSubscriber::drop_subscriber(event_handle_t handle) { - if ((handle == s_subscriber) && (s_subscriber != NULL)) { - delete s_subscriber; - s_subscriber = NULL; + if ((handle == s_subscriber.get()) && (s_subscriber != NULL)) { + s_subscriber.reset(); } } +event_receive_op_t +EventSubscriber::do_receive(event_handle_t handle) +{ + event_receive_op_t op; + + if ((handle == s_subscriber.get()) && (s_subscriber != NULL)) { + op.rc = s_subscriber->event_receive(op.key, op.params, op.missed_cnt); + } + else { + op.rc = -1; + } + return op; +} + EventSubscriber::EventSubscriber(): m_zmq_ctx(NULL), m_socket(NULL), m_cache_read(false) {}; @@ -442,10 +465,6 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ } - -/* Expect only one subscriber per process */ -EventSubscriber *EventSubscriber::s_subscriber = NULL; - event_handle_t events_init_subscriber(bool use_cache, int recv_timeout, const event_subscribe_sources_t *sources) @@ -462,15 +481,7 @@ events_deinit_subscriber(event_handle_t handle) event_receive_op_t event_receive(event_handle_t handle) { - event_receive_op_t op; - - if ((handle == s_subscriber) && (s_subscriber != NULL)) { - op.rc = s_subscriber->event_receive(op.key, op.params, op.missed_cnt); - } - else { - op.rc = -1; - } - return op; + return EventSubscriber::do_receive(handle); } void * diff --git a/common/events_pi.h b/common/events_pi.h index 4258cb57c..bbb7db2d9 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -47,17 +47,19 @@ class EventPublisher : public events_base public: virtual ~EventPublisher(); - int init(const string event_source); - - int publish(const string event_tag, - const event_params_t *params); - static event_handle_t get_publisher(const string event_source); - static void drop_publisher((event_handle_t handle); + static void drop_publisher(event_handle_t handle); + static int do_publish(event_handle_t handle, const string tag, + const event_params_t *params); private: EventPublisher(); + int init(const string event_source); + + int publish(const string event_tag, + const event_params_t *params); + void *m_zmq_ctx; void *m_socket; @@ -90,22 +92,24 @@ class EventSubscriber : public events_base static EventSubscriber_ptr_t s_subscriber; public: - int init(bool use_cache=false, - int recv_timeout= -1, - const event_subscribe_sources_t *subs_sources=NULL); - virtual ~EventSubscriber(); - int event_receive(string &key, event_params_t ¶ms, int &missed_cnt); - static event_handle_t get_subscriber(bool use_cache, int recv_timeout, const event_subscribe_sources_t *sources); static void drop_subscriber(event_handle_t handle); + static event_receive_op_t do_receive(event_handle_t handle); + private: EventSubscriber(); - + + int init(bool use_cache=false, + int recv_timeout= -1, + const event_subscribe_sources_t *subs_sources=NULL); + + int event_receive(string &key, event_params_t ¶ms, int &missed_cnt); + void *m_zmq_ctx; void *m_socket; From f1a651045ac4661168adaef8310f464a1fe49d79 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 00:40:14 +0000 Subject: [PATCH 45/97] send event as JSON string --- common/events.cpp | 138 ++++++++++++++------------------------- common/events.h | 18 ++++- common/events_common.cpp | 46 +++++++++++++ common/events_common.h | 16 +++-- common/schema.h | 9 +++ 5 files changed, 129 insertions(+), 98 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 49f25ed40..5287e748e 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -98,8 +98,6 @@ int EventPublisher::init(const string event_source) m_event_source = event_source; - m_runtime_id = get_uuid(); - m_socket = sock; out: if (m_socket == NULL) { @@ -127,15 +125,19 @@ EventPublisher::send_evt(const string str_data) { internal_event_t event_data; int rc; + stringstream ss; + + ss << duration_cast(timepoint.time_since_epoch()).count(); event_data[EVENT_STR_DATA] = str_data; event_data[EVENT_RUNTIME_ID] = m_runtime_id; /* A value of 0 will indicate rollover */ ++m_sequence; event_data[EVENT_SEQUENCE] = seq_to_str(m_sequence); + event_data[EVENT_EPOCH] = ss.str(); rc = zmq_message_send(m_socket, m_event_source, event_data); - RET_ON_ERR(rc == 0, "failed to send for tag %s", tag.c_str()); + RET_ON_ERR(rc == 0, "failed to send for tag %s", str_data.substr(0, 20).c_str()); out: return rc; } @@ -145,7 +147,6 @@ int EventPublisher::publish(const string tag, const event_params_t *params) { int rc; - string key(m_event_source + ":" + tag); string str_data; if (m_event_service.is_active()) { @@ -162,14 +163,9 @@ EventPublisher::publish(const string tag, const event_params_t *params) } if (m_runtime_id.empty()) { - uuid_t id; - char uuid_str[UUID_STR_SIZE]; - uuid_generate(id); - uuid_unparse(id, uuid_str); - m_runtime_id = string(uuid_str); + m_runtime_id = get_uuid(); } - /* Check for timestamp in params. If not, provide it. */ string param_str; event_params_t evt_params; @@ -185,34 +181,12 @@ EventPublisher::publish(const string tag, const event_params_t *params) params = &evt_params; } - rc = serialize(*params, param_str); - RET_ON_ERR(rc == 0, "failed to serialize params %s", - map_to_str(*params).c_str()); - - { - map_str_str_t event_str_map = { { key, param_str}}; - - rc = serialize(event_str_map, str_data); - RET_ON_ERR(rc == 0, "failed to serialize event str %s", - map_to_str(event_str_map).c_str()); - } - + str_data = convert_to_json(m_event_source + ":" + tag, params); rc = send_evt(str_data); + RET_ON_ERR(rc == 0, "failed to send event str[%d]= %s", (int)str_data.size(), + str_data.substr(0, 20).c_str()); - { - nlohmann::json msg = nlohmann::json::object(); - { - nlohmann::json params_data = nlohmann::json::object(); - - for (event_params_t::const_iterator itc = params->begin(); - itc != params->end(); ++itc) { - params_data[itc->first] = itc->second; - } - msg[key] = params_data; - } - string json_str(msg.dump()); - SWSS_LOG_INFO("EVENT_PUBLISHED: %s", json_str.c_str()); - } + SWSS_LOG_INFO("EVENT_PUBLISHED: %s", str_data.sunbstr(0, 80).c_str()); out: return rc; @@ -273,10 +247,7 @@ EventSubscriber::do_receive(event_handle_t handle) event_receive_op_t op; if ((handle == s_subscriber.get()) && (s_subscriber != NULL)) { - op.rc = s_subscriber->event_receive(op.key, op.params, op.missed_cnt); - } - else { - op.rc = -1; + op = s_subscriber->event_receive(); } return op; } @@ -421,15 +392,13 @@ EventSubscriber::prune_track() } -int -EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_cnt) +event_receive_op_t +EventSubscriber::event_receive() { - int rc = 0; - key.clear(); - event_params_t().swap(params); - missed_cnt = 0; + event_receive_op_t evt; + int missed_cnt = 0; - while (key.empty()) { + while (evt.event.empty()) { internal_event_t event_data; if (m_cache_read && m_from_cache.empty()) { @@ -486,22 +455,11 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ if (event_data[EVENT_STR_DATA].compare(0, EVENT_STR_CTRL_PREFIX_SZ, EVENT_STR_CTRL_PREFIX) != 0) { if (this_missed_cnt >= 0) { - map_str_str_t ev; - - rc = deserialize(event_data[EVENT_STR_DATA], ev); - RET_ON_ERR(rc == 0, "Failed to deserialize %s", - event_data[EVENT_STR_DATA].substr(0, 32).c_str()); - - if (ev.size() != 1) rc = -1; - RET_ON_ERR(rc == 0, "Expect string (%s) deserialize to one key", - event_data[EVENT_STR_DATA].substr(0, 32).c_str()); - - key = ev.begin()->first; - - rc = deserialize(ev.begin()->second, params); - RET_ON_ERR(rc == 0, "failed to deserialize params %s", - ev.begin()->second.substr(0, 32).c_str()); - + istringstream iss(event_data[EVENT_EPOCH]); + + evt.event = event_data[EVENT_STR_DATA]; + evt.publish_epoch << iss; + m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); } else { @@ -517,8 +475,9 @@ EventSubscriber::event_receive(string &key, event_params_t ¶ms, int &missed_ } } out: - return rc; - + evt.rc = rc; + evt.missed_cnt = missed_cnt; + return evt; } event_handle_t @@ -635,8 +594,7 @@ events_deinit_subscriber_wrap(void *handle) int -event_receive_wrap(void *handle, char *event_str, - int event_str_sz, char *missed_cnt_str, int missed_cnt_str_sz) +event_receive_wrap(void *handle, char *event_str, int event_str_sz) { event_receive_op_t evt; int rc = 0; @@ -647,30 +605,11 @@ event_receive_wrap(void *handle, char *event_str, evt = event_receive(handle); if (evt.rc == 0) { - nlohmann::json res = nlohmann::json::object(); - - { - nlohmann::json params_data = nlohmann::json::object(); - for (event_params_t::const_iterator itc = evt.params.begin(); itc != evt.params.end(); ++itc) { - params_data[itc->first] = itc->second; - } - res[evt.key] = params_data; - } - string json_str(res.dump()); - rc = snprintf(event_str, event_str_sz, "%s", json_str.c_str()); - if (rc >= event_str_sz) { - SWSS_LOG_ERROR("truncated event buffer.need=%d given=%d", - rc, event_str_sz); - event_str[event_str_sz-1] = 0; - } - - int rc_missed = snprintf(missed_cnt_str, missed_cnt_str_sz, "%d", evt.missed_cnt); - if (rc_missed >= missed_cnt_str_sz) { - SWSS_LOG_ERROR("missed cnt (%d) buffer.need=%d given=%d", - evt.missed_cnt, rc_missed, missed_cnt_str_sz); - missed_cnt_str[missed_cnt_str_sz-1] = 0; - } + string rcv_str(evt.to_json()); + strncpy(event_str, rcv_str.c_str(), event_str_sz); + event_str[event_str-1] = 0; + rc = rcv_str.size(); } else if (evt.rc > 0) { // timeout @@ -692,4 +631,23 @@ void swssSetLogPriority(int pri) swss::Logger::setMinPrio((swss::Logger::Priority) pri); } +string +event_receive_op_t::to_json() +{ + nlohmann::json res = nlohmann::json::object(); + + res[RC_KEY] = rc; + res[EVENT_KEY] = event; + res[MISSED_KEY] = missed_cnt; + res[EPOCH_KEY] = publish_epoch; + + return res.dump(); +} + + +int +event_receive_op_t::parse_event(string &key, map_str_str_t ¶ms) +{ + return convert_from_json(event, key, params); +} diff --git a/common/events.h b/common/events.h index dab3289f0..a22ecf90e 100644 --- a/common/events.h +++ b/common/events.h @@ -151,11 +151,23 @@ event_handle_t events_init_subscriber(bool use_cache=false, void events_deinit_subscriber(event_handle_t handle); -typedef struct { +typedef struct event_receive_op { + event_receive_op() : rc(-1), missed_cnt(0), publish_epoch(0) {} + int rc; /* Return value of event_receive */ - std::string key; /* key */ - event_params_t params; /* Params received */ + std::string event; /* Event as JSON string */ int missed_cnt; /* missed count */ + uint64_t publish_epoch; /* Epoch timepoint of publish */ + + string to_json(); + + int parse_event(string &key, map_str_str_t ¶ms); + + /* JSON Keys */ + const string RC_KEY = "rc"; + const string EVENT_KEY = "event"; + const string MISSED_KEY = "missed_cnt"; + const string EPOCH_KEY = "publish_epoch"; } event_receive_op_t; /* diff --git a/common/events_common.cpp b/common/events_common.cpp index 0f3ad20ad..4196660dc 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -102,3 +102,49 @@ get_timestamp() return ss.str(); } +string +convert_to_json(const string key, const map_str_str_t ¶ms) +{ + nlohmann::json msg = nlohmann::json::object(); + nlohmann::json params_data = nlohmann::json::object(); + + for (map_str_str_t::const_iterator itc = params.begin(); + itc != params.end(); ++itc) { + params_data[itc->first] = itc->second; + } + msg[key] = params_data; + } + return json_str(msg.dump()); +} + +int +convert_from_json(const string json_str, string &key, map_str_str_t ¶ms) +{ + const auto &data = nlohmann::json::parse(json_str); + + if (data.size() != 1) { + SWSS_LOG_ERROR("Invalid json str(%s). Expect one key sz=%d", + json_str.substr(0, 20).c_str(), (int)data.size()); + return -1; + } + key = it.key(); + const auto ¶ms = *it; + + if (!params.is_object()) { + SWSS_LOG_ERROR("Invalid json str(%s). Expect object as val", + json_str.substr(0, 20).c_str()); + return -1; + } + + for (auto itp = params.cbegin(); itp != params.cend(); ++itp) { + if ((*itp).is_string()) { + params[itp.key()] = itp.value(); + } + else { + SWSS_LOG_ERROR("Invalid json str(%s). Expect params value as string", + json_str.substr(0, 20).c_str()); + return -1; + } + } + return 0; +} diff --git a/common/events_common.h b/common/events_common.h index 877cbddb1..727a3603b 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -27,8 +27,6 @@ using namespace chrono; #define ERR_MESSAGE_INVALID -2 #define ERR_OTHER -1 -#define UINT32_MAX ((uint32_t)-1) - /* * Max count of possible concurrent event publishers * We maintain a cache of last seen sequence number per publisher. @@ -185,6 +183,7 @@ const string get_timestamp(); #define EVENT_STR_DATA "d" #define EVENT_RUNTIME_ID "r" #define EVENT_SEQUENCE "s" +#define EVENT_EPOCH "t" typedef map internal_event_t; @@ -196,9 +195,10 @@ typedef string runtime_id_t; /* * internal_event_t internal_event_ref = { - * { EVENT_STR_DATA, "" }, - * { EVENT_RUNTIME_ID, "" }, - * { EVENT_SEQUENCE, "" } }; + * { EVENT_STR_DATA, "" }, + * { EVENT_RUNTIME_ID, "" }, + * { EVENT_SEQUENCE, "" }, + * { EVENT_EPOCH, "" } }; */ /* @@ -432,6 +432,12 @@ zmq_message_read(void *sock, int flag, P1 &pt1, P2 &pt2) return render.zmq_message_read(sock, flag, pt1, pt2); } +/* Convert {: < params >tttt a JSON string */ +string convert_to_json(const string key, const map_str_str_t ¶ms); + +/* Parse JSON string into {: < params >} */ +int convert_from_json(const string json_str, string &key, map_str_str_t ¶ms); + /* * Cache drain timeout. * diff --git a/common/schema.h b/common/schema.h index 3b32c8247..017352ce4 100644 --- a/common/schema.h +++ b/common/schema.h @@ -182,12 +182,21 @@ namespace swss { #define COUNTERS_TWICE_NAPT_TABLE "COUNTERS_TWICE_NAPT" #define COUNTERS_GLOBAL_NAT_TABLE "COUNTERS_GLOBAL_NAT" +#define COUNTERS_EVENTS_TABLE "COUNTERS_EVENTS" + #define PERIODIC_WATERMARKS_TABLE "PERIODIC_WATERMARKS" #define PERSISTENT_WATERMARKS_TABLE "PERSISTENT_WATERMARKS" #define USER_WATERMARKS_TABLE "USER_WATERMARKS" #define RATES_TABLE "RATES" +/***** EVENTS COUNTER KEYS *****/ +#define COUNTERS_EVENTS_PUBLISHED "published" +#define COUNTERS_EVENTS_MISSED_SLOW_RCVR "missed_by_slow_receiver" +#define COUNTERS_EVENTS_MISSED_INTERNAL "missed_internal" +#define COUNTERS_EVENTS_MISSED_CACHE "missed_to_cache" +#define COUNTERS_EVENTS_LATENCY "latency_in_ms" + /***** LOGLEVEL DATABASE *****/ #define DAEMON_TABLE_NAME "DAEMON_TABLE" From 72d079e95b100d428907f0e257e3faad3c290a0d Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 03:36:14 +0000 Subject: [PATCH 46/97] syntax --- common/events.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/events.h b/common/events.h index a22ecf90e..6b78aed13 100644 --- a/common/events.h +++ b/common/events.h @@ -159,15 +159,15 @@ typedef struct event_receive_op { int missed_cnt; /* missed count */ uint64_t publish_epoch; /* Epoch timepoint of publish */ - string to_json(); + std::string to_json(); - int parse_event(string &key, map_str_str_t ¶ms); + int parse_event(string &key, event_params_t ¶ms); /* JSON Keys */ - const string RC_KEY = "rc"; - const string EVENT_KEY = "event"; - const string MISSED_KEY = "missed_cnt"; - const string EPOCH_KEY = "publish_epoch"; + const std::string RC_KEY = "rc"; + const std::string EVENT_KEY = "event"; + const std::string MISSED_KEY = "missed_cnt"; + const std::string EPOCH_KEY = "publish_epoch"; } event_receive_op_t; /* From 9e4b7db3cb45422c39d141b89b9d17596564af2c Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 03:55:44 +0000 Subject: [PATCH 47/97] syntax --- common/events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/events.h b/common/events.h index 6b78aed13..f13e36163 100644 --- a/common/events.h +++ b/common/events.h @@ -161,7 +161,7 @@ typedef struct event_receive_op { std::string to_json(); - int parse_event(string &key, event_params_t ¶ms); + int parse_event(std::string &key, event_params_t ¶ms); /* JSON Keys */ const std::string RC_KEY = "rc"; From 1428c18f8d76419eaeb3812c154e272f9ea2d66e Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 04:03:22 +0000 Subject: [PATCH 48/97] syntax --- common/events.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/events.cpp b/common/events.cpp index 5287e748e..02c5bef5d 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -127,6 +127,7 @@ EventPublisher::send_evt(const string str_data) int rc; stringstream ss; + auto timepoint = system_clock::now(); ss << duration_cast(timepoint.time_since_epoch()).count(); event_data[EVENT_STR_DATA] = str_data; @@ -181,7 +182,7 @@ EventPublisher::publish(const string tag, const event_params_t *params) params = &evt_params; } - str_data = convert_to_json(m_event_source + ":" + tag, params); + str_data = convert_to_json(m_event_source + ":" + tag, *params); rc = send_evt(str_data); RET_ON_ERR(rc == 0, "failed to send event str[%d]= %s", (int)str_data.size(), str_data.substr(0, 20).c_str()); From 3e330d72023564a74ec3e80e647e00e58cfe1620 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 04:08:57 +0000 Subject: [PATCH 49/97] syntax --- common/events_common.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/events_common.cpp b/common/events_common.cpp index 4196660dc..0a9dc9f69 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -110,10 +110,9 @@ convert_to_json(const string key, const map_str_str_t ¶ms) for (map_str_str_t::const_iterator itc = params.begin(); itc != params.end(); ++itc) { - params_data[itc->first] = itc->second; - } - msg[key] = params_data; + params_data[itc->first] = itc->second; } + msg[key] = params_data; return json_str(msg.dump()); } @@ -148,3 +147,4 @@ convert_from_json(const string json_str, string &key, map_str_str_t ¶ms) } return 0; } + From 8e0553b1421a32f8577762d675d236bb836f3083 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 04:31:03 +0000 Subject: [PATCH 50/97] syntax --- common/events.cpp | 2 +- common/events_common.cpp | 9 +++++---- common/events_pi.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 02c5bef5d..9b78f6c3d 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -187,7 +187,7 @@ EventPublisher::publish(const string tag, const event_params_t *params) RET_ON_ERR(rc == 0, "failed to send event str[%d]= %s", (int)str_data.size(), str_data.substr(0, 20).c_str()); - SWSS_LOG_INFO("EVENT_PUBLISHED: %s", str_data.sunbstr(0, 80).c_str()); + SWSS_LOG_INFO("EVENT_PUBLISHED: %s", str_data.substr(0, 80).c_str()); out: return rc; diff --git a/common/events_common.cpp b/common/events_common.cpp index 0a9dc9f69..27d4a2276 100644 --- a/common/events_common.cpp +++ b/common/events_common.cpp @@ -113,7 +113,7 @@ convert_to_json(const string key, const map_str_str_t ¶ms) params_data[itc->first] = itc->second; } msg[key] = params_data; - return json_str(msg.dump()); + return msg.dump(); } int @@ -126,16 +126,17 @@ convert_from_json(const string json_str, string &key, map_str_str_t ¶ms) json_str.substr(0, 20).c_str(), (int)data.size()); return -1; } + auto it = data.cbegin(); key = it.key(); - const auto ¶ms = *it; + const auto ¶ms_data = *it; - if (!params.is_object()) { + if (!params_data.is_object()) { SWSS_LOG_ERROR("Invalid json str(%s). Expect object as val", json_str.substr(0, 20).c_str()); return -1; } - for (auto itp = params.cbegin(); itp != params.cend(); ++itp) { + for (auto itp = params_data.cbegin(); itp != params_data.cend(); ++itp) { if ((*itp).is_string()) { params[itp.key()] = itp.value(); } diff --git a/common/events_pi.h b/common/events_pi.h index 72c0aaf47..76a2ddcf5 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -108,7 +108,7 @@ class EventSubscriber : public events_base int recv_timeout= -1, const event_subscribe_sources_t *subs_sources=NULL); - int event_receive(string &key, event_params_t ¶ms, int &missed_cnt); + int event_receive(); void *m_zmq_ctx; void *m_socket; From 8ff311f8bb7a8ee77165bd0a57991c1056668287 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 17:43:03 +0000 Subject: [PATCH 51/97] compile fix --- common/events.cpp | 10 +++++----- common/events.h | 12 ++++++------ common/events_pi.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 9b78f6c3d..05df084eb 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -600,10 +600,10 @@ event_receive_wrap(void *handle, char *event_str, int event_str_sz) event_receive_op_t evt; int rc = 0; - SWSS_LOG_DEBUG("events_receive_wrap handle=%p event-sz=%d missed-sz=%d\n", - handle, event_str_sz, missed_cnt_str_sz); + SWSS_LOG_DEBUG("events_receive_wrap handle=%p event-sz=%d\n", + handle, event_str_sz); - evt = event_receive(handle); + evt = EventSubscriber::do_receive(handle); if (evt.rc == 0) { @@ -620,8 +620,8 @@ event_receive_wrap(void *handle, char *event_str, int event_str_sz) rc = evt.rc; } - SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s missed=%s\n", - rc, event_str, missed_cnt_str); + SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s\n", + rc, event_str); return rc; } diff --git a/common/events.h b/common/events.h index f13e36163..bbd410634 100644 --- a/common/events.h +++ b/common/events.h @@ -159,15 +159,15 @@ typedef struct event_receive_op { int missed_cnt; /* missed count */ uint64_t publish_epoch; /* Epoch timepoint of publish */ - std::string to_json(); + std::string to_json() const; - int parse_event(std::string &key, event_params_t ¶ms); + int parse_event(std::string &key, event_params_t ¶ms) const; /* JSON Keys */ - const std::string RC_KEY = "rc"; - const std::string EVENT_KEY = "event"; - const std::string MISSED_KEY = "missed_cnt"; - const std::string EPOCH_KEY = "publish_epoch"; + static const std::string RC_KEY = "rc"; + static const std::string EVENT_KEY = "event"; + static const std::string MISSED_KEY = "missed_cnt"; + static const std::string EPOCH_KEY = "publish_epoch"; } event_receive_op_t; /* diff --git a/common/events_pi.h b/common/events_pi.h index 76a2ddcf5..f48ff846c 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -108,7 +108,7 @@ class EventSubscriber : public events_base int recv_timeout= -1, const event_subscribe_sources_t *subs_sources=NULL); - int event_receive(); + event_receive_op_t event_receive(); void *m_zmq_ctx; void *m_socket; From a560586ebf2dcc531cfc3d42f078021f5035065b Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 17:57:53 +0000 Subject: [PATCH 52/97] compile fix --- common/events.cpp | 5 +++++ common/events.h | 8 ++++---- common/events_wrap.h | 29 ++++++++--------------------- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 05df084eb..e2a9e0af6 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -632,6 +632,11 @@ void swssSetLogPriority(int pri) swss::Logger::setMinPrio((swss::Logger::Priority) pri); } +event_receive_op::RC_KEY = "rc"; +event_receive_op::EVENT_KEY = "event"; +event_receive_op::MISSED_KEY = "missed_cnt"; +event_receive_op::EPOCH_KEY = "publish_epoch"; + string event_receive_op_t::to_json() { diff --git a/common/events.h b/common/events.h index bbd410634..329e9e25c 100644 --- a/common/events.h +++ b/common/events.h @@ -164,10 +164,10 @@ typedef struct event_receive_op { int parse_event(std::string &key, event_params_t ¶ms) const; /* JSON Keys */ - static const std::string RC_KEY = "rc"; - static const std::string EVENT_KEY = "event"; - static const std::string MISSED_KEY = "missed_cnt"; - static const std::string EPOCH_KEY = "publish_epoch"; + static const std::string RC_KEY; + static const std::string EVENT_KEY; + static const std::string MISSED_KEY; + static const std::string EPOCH_KEY; } event_receive_op_t; /* diff --git a/common/events_wrap.h b/common/events_wrap.h index ac91f6ca7..480ed9bac 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -107,34 +107,21 @@ void events_deinit_subscriber_wrap(void *handle); * * input: * handle - Handle obtained from init subscriber - * event_str: - * Buffer for receiving event formatted as below. - * : { - * - * } - * e.g: '{ - * "sonic-events-bgp:bgp-state": { - * "timestamp": "2022-08-17T02:39:21.286611Z", - * "ip": "100.126.188.90", - * "status": "down" - * } - * }' - * event_str_sz: - * Size of the buffer for receiving event. + * event_receive_op_str: + * JSON string of event_receive_op_t * - * missed_cnt: - * Buffer to receive missed count as int converted to string. - * - * missed_cnt_sz: - * Size of the missed_cnt buffer. + * event_receive_op_sz: + * Size of event_receive_op_str buffer * * Return: + * Count of bytes required in buffer to copy. + * If this size > event_receive_op_sz, it implies truncation. + * * > 0 -- Implies received an event * = 0 -- implies no event received due to timeout * < 0 -- Implies failure. Absoulte value is the error code */ -int event_receive_wrap(void *handle, char *event_str, - int event_str_sz, char *missed_cnt, int missed_cnt_sz); +int event_receive_wrap(void *handle, char *event_str, int event_str_sz); /* * Set SWSS log priority From 8c996514990347f156dc202c5be9b442f0ccbc85 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 18:21:37 +0000 Subject: [PATCH 53/97] compile fix --- common/events.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/events.cpp b/common/events.cpp index e2a9e0af6..d4ac36d6c 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -398,6 +398,7 @@ EventSubscriber::event_receive() { event_receive_op_t evt; int missed_cnt = 0; + int rc = 0; while (evt.event.empty()) { internal_event_t event_data; @@ -459,7 +460,7 @@ EventSubscriber::event_receive() istringstream iss(event_data[EVENT_EPOCH]); evt.event = event_data[EVENT_STR_DATA]; - evt.publish_epoch << iss; + iss >> evt.publish_epoch; m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); } From de179f305af2413d05b35e53a9215b1a571406ac Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 18:26:06 +0000 Subject: [PATCH 54/97] compile fix --- common/events.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index d4ac36d6c..eb730cc9c 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -610,7 +610,7 @@ event_receive_wrap(void *handle, char *event_str, int event_str_sz) string rcv_str(evt.to_json()); strncpy(event_str, rcv_str.c_str(), event_str_sz); - event_str[event_str-1] = 0; + event_str[event_str_sz-1] = 0; rc = rcv_str.size(); } else if (evt.rc > 0) { @@ -633,10 +633,10 @@ void swssSetLogPriority(int pri) swss::Logger::setMinPrio((swss::Logger::Priority) pri); } -event_receive_op::RC_KEY = "rc"; -event_receive_op::EVENT_KEY = "event"; -event_receive_op::MISSED_KEY = "missed_cnt"; -event_receive_op::EPOCH_KEY = "publish_epoch"; +string event_receive_op::RC_KEY = "rc"; +string event_receive_op::EVENT_KEY = "event"; +string event_receive_op::MISSED_KEY = "missed_cnt"; +string event_receive_op::EPOCH_KEY = "publish_epoch"; string event_receive_op_t::to_json() From 100ece73bc8743d7f70bb15362c733dcf0c76420 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 18:37:00 +0000 Subject: [PATCH 55/97] compile fix --- common/events.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index eb730cc9c..39a2172dd 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -611,7 +611,7 @@ event_receive_wrap(void *handle, char *event_str, int event_str_sz) string rcv_str(evt.to_json()); strncpy(event_str, rcv_str.c_str(), event_str_sz); event_str[event_str_sz-1] = 0; - rc = rcv_str.size(); + rc = (int)rcv_str.size(); } else if (evt.rc > 0) { // timeout @@ -633,13 +633,13 @@ void swssSetLogPriority(int pri) swss::Logger::setMinPrio((swss::Logger::Priority) pri); } -string event_receive_op::RC_KEY = "rc"; -string event_receive_op::EVENT_KEY = "event"; -string event_receive_op::MISSED_KEY = "missed_cnt"; -string event_receive_op::EPOCH_KEY = "publish_epoch"; +const string event_receive_op::RC_KEY = "rc"; +const string event_receive_op::EVENT_KEY = "event"; +const string event_receive_op::MISSED_KEY = "missed_cnt"; +const string event_receive_op::EPOCH_KEY = "publish_epoch"; string -event_receive_op_t::to_json() +event_receive_op_t::to_json() const { nlohmann::json res = nlohmann::json::object(); @@ -653,7 +653,7 @@ event_receive_op_t::to_json() int -event_receive_op_t::parse_event(string &key, map_str_str_t ¶ms) +event_receive_op_t::parse_event(string &key, map_str_str_t ¶ms) const { return convert_from_json(event, key, params); } From 3887e614a7aa05884ead0596a3158d673f14b627 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 22:21:36 +0000 Subject: [PATCH 56/97] compile fix --- common/events.cpp | 12 ++++++++++++ common/events.h | 2 ++ tests/events_ut.cpp | 28 +++++++++++----------------- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 39a2172dd..25ee0f262 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -652,6 +652,18 @@ event_receive_op_t::to_json() const } +string +event_receive_op_t::from_json(const char *json_str) +{ + const auto &data = nlohmann::json::parse(json_str); + + rc = data.value(RC_KEY, -1) + event = data.value(EVENT_KEY, "") + missed_cnt = data.value(MISSED_KEY, 0) + publish_epoch = data.value(EVENT_EPOCH, 0) +} + + int event_receive_op_t::parse_event(string &key, map_str_str_t ¶ms) const { diff --git a/common/events.h b/common/events.h index 329e9e25c..bb46f5143 100644 --- a/common/events.h +++ b/common/events.h @@ -161,6 +161,8 @@ typedef struct event_receive_op { std::string to_json() const; + std::string from_json(const char *); + int parse_event(std::string &key, event_params_t ¶ms) const; /* JSON Keys */ diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 697f33941..628c7bca8 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -607,27 +607,17 @@ void do_test_subscribe(bool wrap) for(i=0; true; ++i) { string exp_key; event_receive_op_t evt; + string key; + event_params_t params; if (wrap) { char event_str[1024]; - char missed_cnt[100]; - int rc = event_receive_wrap(hsub, event_str, sizeof(event_str), - missed_cnt, sizeof(missed_cnt)); + int rc = event_receive_wrap(hsub, event_str, sizeof(event_str)); + EXPECT_LT(rc, sizeof(event_str)); if (rc != 0) { - const auto &data = nlohmann::json::parse(event_str); - EXPECT_EQ(1, data.size()); - - auto it = data.cbegin(); - - evt.key = it.key(); - auto val = it.value(); - for (auto itp = val.begin(); itp != val.end(); ++itp) { - evt.params[itp.key()] = itp.value(); - } - evt.rc = 0; - evt.missed_cnt = stoi(string(missed_cnt)); + evt.from_json(event_str); } else if (rc == 0) { evt.rc = EAGAIN; @@ -645,13 +635,17 @@ void do_test_subscribe(bool wrap) break; } - EXPECT_EQ(ldata[i].params, evt.params); + evt.parse_event(key, params); + + EXPECT_EQ(ldata[i].params, params); exp_key = ldata[i].source + ":" + ldata[i].tag; - EXPECT_EQ(exp_key, evt.key); + EXPECT_EQ(exp_key, key); EXPECT_EQ(ldata[i].missed_cnt, evt.missed_cnt); + + EXPECT_NE(0, evt.publish_epoch); } EXPECT_EQ(i, (int)ARRAY_SIZE(ldata)); From c6fdd80af03cbc7729d32bc8e2beb3897aeb6025 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 22:25:27 +0000 Subject: [PATCH 57/97] compile fix --- common/events.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 25ee0f262..86bd078d9 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -657,10 +657,10 @@ event_receive_op_t::from_json(const char *json_str) { const auto &data = nlohmann::json::parse(json_str); - rc = data.value(RC_KEY, -1) - event = data.value(EVENT_KEY, "") - missed_cnt = data.value(MISSED_KEY, 0) - publish_epoch = data.value(EVENT_EPOCH, 0) + rc = data.value(RC_KEY, -1); + event = data.value(EVENT_KEY, ""); + missed_cnt = data.value(MISSED_KEY, 0); + publish_epoch = data.value(EVENT_EPOCH, 0); } From 88156a1ae362fe76e899090276174a12c587f7aa Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 22 Jul 2022 22:28:52 +0000 Subject: [PATCH 58/97] compile fix --- common/events.cpp | 2 +- common/events.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 86bd078d9..1d8d0665b 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -652,7 +652,7 @@ event_receive_op_t::to_json() const } -string +void event_receive_op_t::from_json(const char *json_str) { const auto &data = nlohmann::json::parse(json_str); diff --git a/common/events.h b/common/events.h index bb46f5143..98d7c6e83 100644 --- a/common/events.h +++ b/common/events.h @@ -161,7 +161,7 @@ typedef struct event_receive_op { std::string to_json() const; - std::string from_json(const char *); + void from_json(const char *); int parse_event(std::string &key, event_params_t ¶ms) const; From 9fcf2f086effcee0c9b9b5b39365554e6ca89d39 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 00:18:35 +0000 Subject: [PATCH 59/97] changing wrap signature to use struct instead of JSON string --- common/events.cpp | 216 ++++++++++++++++++------------------------- common/events.h | 45 ++++----- common/events_pi.h | 5 +- common/events_wrap.h | 90 +++++++++--------- 4 files changed, 153 insertions(+), 203 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 1d8d0665b..c1795338d 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -127,6 +127,10 @@ EventPublisher::send_evt(const string str_data) int rc; stringstream ss; + if (str_data.size() > EVENT_MAXSZ) { + SWSS_LOG_ERROR("event size (%d) > expected max(%d). Still published.", + str_data.size(), EVENT_MAXSZ); + } auto timepoint = system_clock::now(); ss << duration_cast(timepoint.time_since_epoch()).count(); @@ -242,15 +246,17 @@ EventSubscriber::drop_subscriber(event_handle_t handle) } -event_receive_op_t -EventSubscriber::do_receive(event_handle_t handle) +int +EventSubscriber::do_receive(event_handle_t handle, event_receive_op_t &evt) { - event_receive_op_t op; + int rc = -1; - if ((handle == s_subscriber.get()) && (s_subscriber != NULL)) { - op = s_subscriber->event_receive(); - } - return op; + RET_ON_ERR ((handle == s_subscriber.get()) && (s_subscriber != NULL), + "Invalid handle for receive"); + + rc = s_subscriber->event_receive(evt); +out: + return rc; } EventSubscriber::EventSubscriber(): m_zmq_ctx(NULL), m_socket(NULL), @@ -393,14 +399,13 @@ EventSubscriber::prune_track() } -event_receive_op_t -EventSubscriber::event_receive() +int +EventSubscriber::event_receive(event_receive_op_t &evt) { - event_receive_op_t evt; int missed_cnt = 0; int rc = 0; - while (evt.event.empty()) { + while (true) { internal_event_t event_data; if (m_cache_read && m_from_cache.empty()) { @@ -452,21 +457,33 @@ EventSubscriber::event_receive() prune_track(); } } + + if (this_missed_cnt < 0) { + continue; /* We read duplicate */ + } missed_cnt += this_missed_cnt; + /* We have a valid publised or control event */ + if (event_data[EVENT_STR_DATA].compare(0, EVENT_STR_CTRL_PREFIX_SZ, EVENT_STR_CTRL_PREFIX) != 0) { - if (this_missed_cnt >= 0) { + if (evt.event_sz > event_data[EVENT_STR_DATA].size()) { istringstream iss(event_data[EVENT_EPOCH]); - evt.event = event_data[EVENT_STR_DATA]; + /* + * event_sz - string size is verified against event string. + * Hence strncpy will put null at the end. + */ + strncpy(evt.event_str, event_data[EVENT_STR_DATA], evt.event_sz); iss >> evt.publish_epoch; - - m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); - } - else { - /* negative value implies duplicate; Possibly seen from cache */ + } else { + missed_cnt += 1; + SWSS_LOG_ERROR( + "event size (%d) > expected (%d)", + event_data[EVENT_STR_DATA].size(), evt.event_sz); } + m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); + break; } else { /* This is control message */ if (event_data[EVENT_STR_DATA] == EVENT_STR_CTRL_DEINIT) { @@ -477,9 +494,12 @@ EventSubscriber::event_receive() } } out: - evt.rc = rc; + /* + * Returns on receiving event or timeout or anyother receive failure. + * Missed count is valid value, even when rc != 0 + */ evt.missed_cnt = missed_cnt; - return evt; + return rc; } event_handle_t @@ -495,30 +515,27 @@ events_deinit_subscriber(event_handle_t handle) EventSubscriber::drop_subscriber(handle); } -event_receive_op_t -event_receive(event_handle_t handle) +int +event_receive(event_handle_t handle, + event_receive_op_t *evt) { - return EventSubscriber::do_receive(handle); + int rc = -1; + RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); + rc = EventSubscriber::do_receive(handle, *evt); +out: + return rc; } void * -events_init_publisher_wrap(const char *args) +events_init_publisher_wrap(const char *event_source) { - SWSS_LOG_DEBUG("events_init_publisher_wrap: args=%s", - (args != NULL ? args : "")); + SWSS_LOG_DEBUG("events_init_publisher_wrap: event_source=%s", + (event_source != NULL ? event_source : "")); - if (args == NULL) { + if ((event_source == NULL) || (*event_source == 0)) { return NULL; } - const auto &data = nlohmann::json::parse(args); - - string source; - for (auto it = data.cbegin(); it != data.cend(); ++it) { - if ((it.key() == ARGS_SOURCE) && (*it).is_string()) { - source = it.value(); - } - } - return events_init_publisher(source); + return events_init_publisher(event_source); } @@ -530,57 +547,50 @@ events_deinit_publisher_wrap(void *handle) int -event_publish_wrap(void *handle, const char *args) +event_publish_wrap(void *handle, const publish_data_t data) { string tag; event_params_t params; - SWSS_LOG_DEBUG("events_init_publisher_wrap: handle=%p args=%s", - handle, (args != NULL ? args : "")); - - if (args == NULL) { + if ((data == NULL) || (data->tag == NULL) || (*data->tag == 0) || + ((data->params_cnt != 0) && (data->params == NULL))) { + SWSS_LOG_ERROR("event_publish_wrap: missing required args); return -1; } - const auto &data = nlohmann::json::parse(args); - for (auto it = data.cbegin(); it != data.cend(); ++it) { - if ((it.key() == ARGS_TAG) && (*it).is_string()) { - tag = it.value(); - } - else if ((it.key() == ARGS_PARAMS) && (*it).is_object()) { - const auto ¶ms_data = *it; - for (auto itp = params_data.cbegin(); itp != params_data.cend(); ++itp) { - if ((*itp).is_string()) { - params[itp.key()] = itp.value(); - } - } + SWSS_LOG_DEBUG("events_init_publisher_wrap: handle=%p tag=%s params_cnt = 0", + handle, data->tag, data->params_cnt); + + tag = string(data->tag); + + for (int i=0, const param_wrap_t *p=data->params; iparams_cnt; ++i,++p) { + if ((p->name == NULL) || (*p->name == 0) || + (p->val == NULL) || (*p->val == 0)) { + SWSS_LOG_ERROR("event_publish_wrap: Missing param key/val"); + return -1; } + params[p->name] = p->val; } - return event_publish(handle, tag, ¶ms); + return event_publish(handle, tag, params.empty() ? NULL : ¶ms); } void * -events_init_subscriber_wrap(const char *args) +events_init_subscriber_wrap(const init_subs_t *init_data) { - bool use_cache = true; + bool use_cache = false; int recv_timeout = -1; event_subscribe_sources_t sources; + void *handle = NULL; - SWSS_LOG_DEBUG("events_init_subsriber_wrap: args:%s", args); + if (init_data != NULL) { + use_cache = init_data->use_cache; + recv_timeout = init_data->recv_timeout; + } - if (args != NULL) { - const auto &data = nlohmann::json::parse(args); + SWSS_LOG_DEBUG("events_init_subsriber_wrap: use_cache=%d timeout=%d", + use_cache, recv_timeout); - for (auto it = data.cbegin(); it != data.cend(); ++it) { - if ((it.key() == ARGS_USE_CACHE) && (*it).is_boolean()) { - use_cache = it.value(); - } - else if ((it.key() == ARGS_RECV_TIMEOUT) && (*it).is_number_integer()) { - recv_timeout = it.value(); - } - } - } - void *handle = events_init_subscriber(use_cache, recv_timeout); + handle = events_init_subscriber(use_cache, recv_timeout); SWSS_LOG_DEBUG("events_init_subscriber_wrap: handle=%p", handle); return handle; } @@ -596,77 +606,27 @@ events_deinit_subscriber_wrap(void *handle) int -event_receive_wrap(void *handle, char *event_str, int event_str_sz) +event_receive_wrap(void *handle, event_receive_op_t *evt) { - event_receive_op_t evt; - int rc = 0; - - SWSS_LOG_DEBUG("events_receive_wrap handle=%p event-sz=%d\n", - handle, event_str_sz); - - evt = EventSubscriber::do_receive(handle); - - if (evt.rc == 0) { - - string rcv_str(evt.to_json()); - strncpy(event_str, rcv_str.c_str(), event_str_sz); - event_str[event_str_sz-1] = 0; - rc = (int)rcv_str.size(); - } - else if (evt.rc > 0) { - // timeout - rc = 0; - } - else { - rc = evt.rc; - } - + int rc = -1; + RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); + rc = EventSubscriber::do_receive(handle, *evt); SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s\n", rc, event_str); - +out: return rc; -} +} void swssSetLogPriority(int pri) { swss::Logger::setMinPrio((swss::Logger::Priority) pri); } -const string event_receive_op::RC_KEY = "rc"; -const string event_receive_op::EVENT_KEY = "event"; -const string event_receive_op::MISSED_KEY = "missed_cnt"; -const string event_receive_op::EPOCH_KEY = "publish_epoch"; - -string -event_receive_op_t::to_json() const -{ - nlohmann::json res = nlohmann::json::object(); - - res[RC_KEY] = rc; - res[EVENT_KEY] = event; - res[MISSED_KEY] = missed_cnt; - res[EPOCH_KEY] = publish_epoch; - - return res.dump(); -} - - -void -event_receive_op_t::from_json(const char *json_str) -{ - const auto &data = nlohmann::json::parse(json_str); - - rc = data.value(RC_KEY, -1); - event = data.value(EVENT_KEY, ""); - missed_cnt = data.value(MISSED_KEY, 0); - publish_epoch = data.value(EVENT_EPOCH, 0); -} - - int -event_receive_op_t::parse_event(string &key, map_str_str_t ¶ms) const +parse_json_event(const string event_str, string &key, + event_params_t ¶ms) const { - return convert_from_json(event, key, params); + return convert_from_json(event_str, key, params); } diff --git a/common/events.h b/common/events.h index 98d7c6e83..da301dd9e 100644 --- a/common/events.h +++ b/common/events.h @@ -5,6 +5,11 @@ #include #include +#include "events_wrap.h" + +/* A json string of event's max size for sanity check. */ +#define EVENT_MAXSZ 1024 + /* * Events library * @@ -150,28 +155,6 @@ event_handle_t events_init_subscriber(bool use_cache=false, */ void events_deinit_subscriber(event_handle_t handle); - -typedef struct event_receive_op { - event_receive_op() : rc(-1), missed_cnt(0), publish_epoch(0) {} - - int rc; /* Return value of event_receive */ - std::string event; /* Event as JSON string */ - int missed_cnt; /* missed count */ - uint64_t publish_epoch; /* Epoch timepoint of publish */ - - std::string to_json() const; - - void from_json(const char *); - - int parse_event(std::string &key, event_params_t ¶ms) const; - - /* JSON Keys */ - static const std::string RC_KEY; - static const std::string EVENT_KEY; - static const std::string MISSED_KEY; - static const std::string EPOCH_KEY; -} event_receive_op_t; - /* * Receive an event. * A blocking call unless the subscriber is created with a timeout. @@ -197,14 +180,15 @@ typedef struct event_receive_op { * handle - As obtained from events_init_subscriber * * output: - * key : - * YANG path as : + * event_receive_op_t: + * Filled with received event, missed count & publish time for this + * event. + * The publish time can be used to compute average latency + * from publish to send to external client. * - * params: - * Parms associated. + * missed count is the count of missed messages from this instance + * of this publisher, before this event. * - * missed_cnt: * Count of missed events from this sender, before this event. Sum of * missed count from all received events will give the total missed. * @@ -214,7 +198,10 @@ typedef struct event_receive_op { * < 0 - For all other failures * */ -event_receive_op_t event_receive(event_handle_t handle); +int event_receive(event_handle_t handle, event_receive_op_t *); +/* Helper to parse JSON event string in event_receive_op_t */ +int parse_json_event(const std::string event_str, std::string &key, + event_params_t ¶ms); #endif /* !_EVENTS_H */ diff --git a/common/events_pi.h b/common/events_pi.h index f48ff846c..88fed94e0 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -99,7 +99,8 @@ class EventSubscriber : public events_base static void drop_subscriber(event_handle_t handle); - static event_receive_op_t do_receive(event_handle_t handle); + static int do_receive(event_handle_t handle, + event_receive_op_t&); private: EventSubscriber(); @@ -108,7 +109,7 @@ class EventSubscriber : public events_base int recv_timeout= -1, const event_subscribe_sources_t *subs_sources=NULL); - event_receive_op_t event_receive(); + int event_receive(event_receive_op_t &); void *m_zmq_ctx; void *m_socket; diff --git a/common/events_wrap.h b/common/events_wrap.h index 480ed9bac..2a1b42a12 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -18,15 +18,14 @@ extern "C" { * Init publisher * * input: - * args: as JSON string as below - * ' { "source" : " 0 -- Handle to use for subsequent calls. * < 0 -- Implies failure. Absoulte value is the error code */ -void * events_init_publisher_wrap(const char *args); +void * events_init_publisher_wrap(const char *event_source); /* @@ -38,58 +37,54 @@ void * events_init_publisher_wrap(const char *args); */ void events_deinit_publisher_wrap(void *handle); +typedef param_wrap { + const char *name; + const char *val; +} param_wrap_t; + +typedef struct publish_data { + const char * tag; + + param_wrap_t * params; + int params_cnt; +} publish_data_t; + /* * Publish an event. * * input: * handle: Handle from init_publisher * - * args: - * '{ "tag" : "", - * "params": { - * - * } - * }' - * e.g: '{ - * "tag": "bgp-state": - * "params": { - * "timestamp": "2022-08-17T02:39:21.286611Z", - * "ip": "100.126.188.90", - * "status": "down" - * } - * }' - * + * data: + * Data to be published. + * Refer core API event_publish for more details. * * Return: * == 0 -- Published successfully * < 0 -- Implies failure. Absoulte value is the error code */ -#define ARGS_TAG "tag" -#define ARGS_PARAMS "params" +int event_publish_wrap(void *handle, const publish_data_t *data); -int event_publish_wrap(void *handle, const char *args); +typedef struct init_subs { + bool use_cache; + int recv_timeout; +} init_subs_t; /* * Init subscriber * * input: - * args: as JSON string as below - * '{ - * "use_cache" : , - * "recv_timeout": , - * }' - * A missing key will be implied for default. - * e.g: '{ "use_cache": false } + * + * init_data: + * Refer core API events_init_subscriber for details. * * Return: * > 0 -- Handle to use for subsequent calls. * < 0 -- Implies failure. Absoulte value is the error code */ -#define ARGS_USE_CACHE "use_cache" -#define ARGS_RECV_TIMEOUT "recv_timeout" -void *events_init_subscriber_wrap(const char *args); +void *events_init_subscriber_wrap(const init_subs_t *init_data); /* @@ -107,21 +102,28 @@ void events_deinit_subscriber_wrap(void *handle); * * input: * handle - Handle obtained from init subscriber - * event_receive_op_str: - * JSON string of event_receive_op_t - * - * event_receive_op_sz: - * Size of event_receive_op_str buffer + * evt: + * Received event. Refer struct for details. * * Return: - * Count of bytes required in buffer to copy. - * If this size > event_receive_op_sz, it implies truncation. - * - * > 0 -- Implies received an event - * = 0 -- implies no event received due to timeout - * < 0 -- Implies failure. Absoulte value is the error code + * 0 - On success + * > 0 - Implies failure due to timeout. + * < 0 - For all other failures */ -int event_receive_wrap(void *handle, char *event_str, int event_str_sz); + +typedef struct event_receive_op { + /* Event as JSON string; c-string to help with C-binding for Go.*/ + char *event_str; + uint32_t event_sz; /* Sizeof event string */ + + uint32_t missed_cnt; /* missed count */ + + uint64_t publish_epoch; /* Epoch timepoint of publish */ + +} event_receive_op_t; + +int +int event_receive_wrap(void *handle, event_receive_op_t *evt); /* * Set SWSS log priority From f50f87877229479af24b34c02cdc8b51f33913b4 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 01:30:10 +0000 Subject: [PATCH 60/97] compile fix --- common/events.cpp | 9 +++++---- common/events_wrap.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index c1795338d..06eb70123 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -129,7 +129,7 @@ EventPublisher::send_evt(const string str_data) if (str_data.size() > EVENT_MAXSZ) { SWSS_LOG_ERROR("event size (%d) > expected max(%d). Still published.", - str_data.size(), EVENT_MAXSZ); + (int)str_data.size(), EVENT_MAXSZ); } auto timepoint = system_clock::now(); ss << duration_cast(timepoint.time_since_epoch()).count(); @@ -474,13 +474,14 @@ EventSubscriber::event_receive(event_receive_op_t &evt) * event_sz - string size is verified against event string. * Hence strncpy will put null at the end. */ - strncpy(evt.event_str, event_data[EVENT_STR_DATA], evt.event_sz); + strncpy(evt.event_str, event_data[EVENT_STR_DATA].c_str(), + evt.event_sz); iss >> evt.publish_epoch; } else { missed_cnt += 1; SWSS_LOG_ERROR( "event size (%d) > expected (%d)", - event_data[EVENT_STR_DATA].size(), evt.event_sz); + (int)event_data[EVENT_STR_DATA].size(), evt.event_sz); } m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); break; @@ -547,7 +548,7 @@ events_deinit_publisher_wrap(void *handle) int -event_publish_wrap(void *handle, const publish_data_t data) +event_publish_wrap(void *handle, const publish_data_t *data) { string tag; event_params_t params; diff --git a/common/events_wrap.h b/common/events_wrap.h index 2a1b42a12..979cb244d 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -37,7 +37,7 @@ void * events_init_publisher_wrap(const char *event_source); */ void events_deinit_publisher_wrap(void *handle); -typedef param_wrap { +typedef struct param_wrap { const char *name; const char *val; } param_wrap_t; From 5e9b4c3cedba7fbf15712a72e98216ce17e544f6 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 01:35:57 +0000 Subject: [PATCH 61/97] compile fix --- common/events.cpp | 2 +- common/events_wrap.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 06eb70123..edffc832d 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -555,7 +555,7 @@ event_publish_wrap(void *handle, const publish_data_t *data) if ((data == NULL) || (data->tag == NULL) || (*data->tag == 0) || ((data->params_cnt != 0) && (data->params == NULL))) { - SWSS_LOG_ERROR("event_publish_wrap: missing required args); + SWSS_LOG_ERROR("event_publish_wrap: missing required args"); return -1; } diff --git a/common/events_wrap.h b/common/events_wrap.h index 979cb244d..960caaae1 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -122,7 +122,7 @@ typedef struct event_receive_op { } event_receive_op_t; -int + int event_receive_wrap(void *handle, event_receive_op_t *evt); /* From 68da0df6111019ac22dbbc49af16d7086338b4e3 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 01:44:56 +0000 Subject: [PATCH 62/97] compile fix --- common/events.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index edffc832d..acd858bab 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -552,6 +552,7 @@ event_publish_wrap(void *handle, const publish_data_t *data) { string tag; event_params_t params; + const param_wrap_t *p; if ((data == NULL) || (data->tag == NULL) || (*data->tag == 0) || ((data->params_cnt != 0) && (data->params == NULL))) { @@ -559,12 +560,12 @@ event_publish_wrap(void *handle, const publish_data_t *data) return -1; } - SWSS_LOG_DEBUG("events_init_publisher_wrap: handle=%p tag=%s params_cnt = 0", + SWSS_LOG_DEBUG("events_init_publisher_wrap: handle=%p tag=%s params_cnt = %d", handle, data->tag, data->params_cnt); tag = string(data->tag); - for (int i=0, const param_wrap_t *p=data->params; iparams_cnt; ++i,++p) { + for (int i=0, p=data->params; iparams_cnt; ++i,++p) { if ((p->name == NULL) || (*p->name == 0) || (p->val == NULL) || (*p->val == 0)) { SWSS_LOG_ERROR("event_publish_wrap: Missing param key/val"); From c997fc5b8d06631f61bee35d0396eec80ea7959d Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 01:49:31 +0000 Subject: [PATCH 63/97] compile fix --- common/events.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/events.cpp b/common/events.cpp index acd858bab..0757ea873 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -565,7 +565,8 @@ event_publish_wrap(void *handle, const publish_data_t *data) tag = string(data->tag); - for (int i=0, p=data->params; iparams_cnt; ++i,++p) { + const param_wrap_t *p = data->params; + for (int i=0; iparams_cnt; ++i,++p) { if ((p->name == NULL) || (*p->name == 0) || (p->val == NULL) || (*p->val == 0)) { SWSS_LOG_ERROR("event_publish_wrap: Missing param key/val"); From 6bb9f33e53c421c8dc936eaf327edaddc7105dba Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 02:29:28 +0000 Subject: [PATCH 64/97] compile fix --- common/events.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 0757ea873..168b069fb 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -552,7 +552,6 @@ event_publish_wrap(void *handle, const publish_data_t *data) { string tag; event_params_t params; - const param_wrap_t *p; if ((data == NULL) || (data->tag == NULL) || (*data->tag == 0) || ((data->params_cnt != 0) && (data->params == NULL))) { @@ -615,7 +614,7 @@ event_receive_wrap(void *handle, event_receive_op_t *evt) RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); rc = EventSubscriber::do_receive(handle, *evt); SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s\n", - rc, event_str); + rc, evt.event_str.c_str()); out: return rc; From 80eda6eb56596cccb9183f3e0d9d319f2e7cac92 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 02:32:15 +0000 Subject: [PATCH 65/97] compile fix --- common/events.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 168b069fb..b78d2925f 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -614,7 +614,7 @@ event_receive_wrap(void *handle, event_receive_op_t *evt) RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); rc = EventSubscriber::do_receive(handle, *evt); SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s\n", - rc, evt.event_str.c_str()); + rc, evt->event_str.c_str()); out: return rc; @@ -627,7 +627,7 @@ void swssSetLogPriority(int pri) int parse_json_event(const string event_str, string &key, - event_params_t ¶ms) const + event_params_t ¶ms) { return convert_from_json(event_str, key, params); } From ed32576308c71a9bd2bb9779a37fc9744b907e83 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 02:34:46 +0000 Subject: [PATCH 66/97] compile fix --- common/events.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/events.cpp b/common/events.cpp index b78d2925f..e016a1c2e 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -614,7 +614,7 @@ event_receive_wrap(void *handle, event_receive_op_t *evt) RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); rc = EventSubscriber::do_receive(handle, *evt); SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s\n", - rc, evt->event_str.c_str()); + rc, evt->event_str); out: return rc; From d1f960c8b19c03784966ba58e85d2d86d42b818b Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 22:37:52 +0000 Subject: [PATCH 67/97] compile fix --- common/events.cpp | 130 ++++++++++++++++++++++++++----------------- common/events.h | 51 ++++++----------- common/events_pi.h | 7 ++- common/events_wrap.h | 32 +++-------- tests/events_ut.cpp | 63 +++++++++------------ 5 files changed, 136 insertions(+), 147 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index e016a1c2e..0c5d53631 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -246,15 +246,16 @@ EventSubscriber::drop_subscriber(event_handle_t handle) } -int -EventSubscriber::do_receive(event_handle_t handle, event_receive_op_t &evt) +EventSubscriber_ptr_t +EventSubscriber::get_instance(event_handle_t handle) { - int rc = -1; + + EventSubscriber_ptr_t ret; RET_ON_ERR ((handle == s_subscriber.get()) && (s_subscriber != NULL), - "Invalid handle for receive"); + "Invalid handle for get_instance"); - rc = s_subscriber->event_receive(evt); + ret = s_subscriber; out: return rc; } @@ -400,10 +401,50 @@ EventSubscriber::prune_track() int -EventSubscriber::event_receive(event_receive_op_t &evt) +EventSubscriber::event_receive(event_receive_op_C_t &op) +{ + string event_str; + int rc = -1; + + RET_ON_ERR (((op.event_sz != 0) && (op.event_str != NULL)), + "Require non null buffer(%p) of non zero size (%u)", + op.event_str, op.event_sz); + + rc = event_receive(event_str, op.missed_cnt, op.publish_epoch_ms); + RET_ON_ERR(rc == 0, "failed to receive event"); + + rc = -1; + RET_ON_ERR(event_str.size() < op.event_sz, + "Event sz (%u) is too large for buffer sz=%u", + event_str.size(), op.event_sz); + + strncpy(op.event_str, event_str, op.event_sz); + rc = 0; +out: + return rc; +} + +int +EventSubscriber::event_receive(event_receive_op_t &op) +{ + string event_str; + int rc = -1; + + rc = event_receive(event_str, op.missed_cnt, op.publish_epoch_ms); + RET_ON_ERR(rc == 0, "failed to receive event"); + + rc = convert_from_json(event_str, op.key, op.params); + RET_ON_ERR(rc == 0, "failed to parse %s", event_str.c_str()); +out: + return rc; +} + +int +EventSubscriber::event_receive(string &event_str, uint32_t &missed_cnt, + uint64_t &publish_epoch) { - int missed_cnt = 0; int rc = 0; + missed_cnt = 0; while (true) { internal_event_t event_data; @@ -467,22 +508,14 @@ EventSubscriber::event_receive(event_receive_op_t &evt) if (event_data[EVENT_STR_DATA].compare(0, EVENT_STR_CTRL_PREFIX_SZ, EVENT_STR_CTRL_PREFIX) != 0) { - if (evt.event_sz > event_data[EVENT_STR_DATA].size()) { - istringstream iss(event_data[EVENT_EPOCH]); - - /* - * event_sz - string size is verified against event string. - * Hence strncpy will put null at the end. - */ - strncpy(evt.event_str, event_data[EVENT_STR_DATA].c_str(), - evt.event_sz); - iss >> evt.publish_epoch; - } else { - missed_cnt += 1; - SWSS_LOG_ERROR( - "event size (%d) > expected (%d)", - (int)event_data[EVENT_STR_DATA].size(), evt.event_sz); - } + istringstream iss(event_data[EVENT_EPOCH]); + + /* + * event_sz - string size is verified against event string. + * Hence strncpy will put null at the end. + */ + event_str = event_data[EVENT_STR_DATA]; + iss >> publish_epoch; m_track[event_data[EVENT_RUNTIME_ID]] = evt_info_t(seq); break; } else { @@ -499,7 +532,6 @@ EventSubscriber::event_receive(event_receive_op_t &evt) * Returns on receiving event or timeout or anyother receive failure. * Missed count is valid value, even when rc != 0 */ - evt.missed_cnt = missed_cnt; return rc; } @@ -517,12 +549,14 @@ events_deinit_subscriber(event_handle_t handle) } int -event_receive(event_handle_t handle, - event_receive_op_t *evt) +event_receive(event_handle_t handle, event_receive_op_t &evt) { int rc = -1; - RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); - rc = EventSubscriber::do_receive(handle, *evt); + + EventSubscriber_ptr_t psubs = EventSubscriber::get_instance(handle); + RET_ON_ERR(psubs != NULL, "Invalid handle %p", handle); + + rc = psubs->event_receive(evt); out: return rc; } @@ -548,30 +582,30 @@ events_deinit_publisher_wrap(void *handle) int -event_publish_wrap(void *handle, const publish_data_t *data) +event_publish_wrap(void *handle, const char *tag_ptr, + const param_C_t *params_ptr, size_t params_cnt) { string tag; event_params_t params; - if ((data == NULL) || (data->tag == NULL) || (*data->tag == 0) || - ((data->params_cnt != 0) && (data->params == NULL))) { + if ((tag_ptr == NULL) || (*tag_ptr == 0) || + ((params_cnt != 0) && (params == NULL))) { SWSS_LOG_ERROR("event_publish_wrap: missing required args"); return -1; } - SWSS_LOG_DEBUG("events_init_publisher_wrap: handle=%p tag=%s params_cnt = %d", - handle, data->tag, data->params_cnt); - - tag = string(data->tag); + SWSS_LOG_DEBUG("events_init_publisher_wrap: handle=%p tag=%s params_cnt = %u", + handle, tag_ptr, params_cnt); - const param_wrap_t *p = data->params; - for (int i=0; iparams_cnt; ++i,++p) { - if ((p->name == NULL) || (*p->name == 0) || - (p->val == NULL) || (*p->val == 0)) { + tag = string(tag_ptr); + for (size_t i=0; iname == NULL) || (*params_ptr->name == 0) || + (params_ptr->val == NULL) || (*params_ptr->val == 0)) { SWSS_LOG_ERROR("event_publish_wrap: Missing param key/val"); return -1; } - params[p->name] = p->val; + params[params_ptr->name] = params_ptr->val; + ++params_ptr; } return event_publish(handle, tag, params.empty() ? NULL : ¶ms); } @@ -611,10 +645,13 @@ int event_receive_wrap(void *handle, event_receive_op_t *evt) { int rc = -1; + RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); - rc = EventSubscriber::do_receive(handle, *evt); - SWSS_LOG_DEBUG("events_receive_wrap rc=%d event_str=%s\n", - rc, evt->event_str); + + EventSubscriber_ptr_t psubs = EventSubscriber::get_instance(handle); + RET_ON_ERR(psubs != NULL, "Invalid handle %p", handle); + + rc = psubs->event_receive(*evt); out: return rc; @@ -625,10 +662,3 @@ void swssSetLogPriority(int pri) swss::Logger::setMinPrio((swss::Logger::Priority) pri); } -int -parse_json_event(const string event_str, string &key, - event_params_t ¶ms) -{ - return convert_from_json(event_str, key, params); -} - diff --git a/common/events.h b/common/events.h index da301dd9e..e1a2cc47b 100644 --- a/common/events.h +++ b/common/events.h @@ -5,11 +5,6 @@ #include #include -#include "events_wrap.h" - -/* A json string of event's max size for sanity check. */ -#define EVENT_MAXSZ 1024 - /* * Events library * @@ -105,6 +100,13 @@ typedef std::map event_params_t; * > 0 - On failure, returns zmq_errno, if failure is zmq socket related. * < 0 - For all other failures */ + +/* + * A sanity check on final JSON string size of event + * An error log will be written for too big events for alert. + */ +#define EVENT_MAXSZ 1024 + int event_publish(event_handle_t handle, const std::string event_tag, const event_params_t *params=NULL); @@ -155,6 +157,14 @@ event_handle_t events_init_subscriber(bool use_cache=false, */ void events_deinit_subscriber(event_handle_t handle); + +typedef struct { + std::string key; /* key */ + event_params_t params; /* Params received */ + uint32_t missed_cnt; /* missed count */ + uint64_t publish_epoch_ms; /* Epoch time in milliseconds */ +} event_receive_op_t; + /* * Receive an event. * A blocking call unless the subscriber is created with a timeout. @@ -163,34 +173,12 @@ void events_deinit_subscriber(event_handle_t handle); * sequence in event to compute missed events count. The missed count * provides the count of events missed from this sender. * - * Received event: - * It is a form of JSON struct, with a single key and - * params as value. The key is : and params is as per schema description for that event. - * - * e.g. - * { "sonic-events-bgp:bgp-state": { - * "ip": "100.126.188.90", - * "status": "down", - * "timestamp": "2022-08-17T02:39:21.286611Z" - * } - * } - * * input: * handle - As obtained from events_init_subscriber * * output: - * event_receive_op_t: - * Filled with received event, missed count & publish time for this - * event. - * The publish time can be used to compute average latency - * from publish to send to external client. - * - * missed count is the count of missed messages from this instance - * of this publisher, before this event. - * - * Count of missed events from this sender, before this event. Sum of - * missed count from all received events will give the total missed. + * evt : + * The entire received event. * * return: * 0 - On success @@ -198,10 +186,7 @@ void events_deinit_subscriber(event_handle_t handle); * < 0 - For all other failures * */ -int event_receive(event_handle_t handle, event_receive_op_t *); +int event_receive(event_handle_t handle, event_receive_op_t &evt); -/* Helper to parse JSON event string in event_receive_op_t */ -int parse_json_event(const std::string event_str, std::string &key, - event_params_t ¶ms); #endif /* !_EVENTS_H */ diff --git a/common/events_pi.h b/common/events_pi.h index 88fed94e0..f241cb613 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -99,9 +99,10 @@ class EventSubscriber : public events_base static void drop_subscriber(event_handle_t handle); - static int do_receive(event_handle_t handle, - event_receive_op_t&); + static EventSubscriber_ptr_t get_instance(event_handle_t handle); + int event_receive(event_receive_op_t &); + int event_receive(event_receive_op_C_t &); private: EventSubscriber(); @@ -109,7 +110,7 @@ class EventSubscriber : public events_base int recv_timeout= -1, const event_subscribe_sources_t *subs_sources=NULL); - int event_receive(event_receive_op_t &); + int event_receive(string &event_str, uint32_t &missed, uint64_t &pub_ms); void *m_zmq_ctx; void *m_socket; diff --git a/common/events_wrap.h b/common/events_wrap.h index 960caaae1..fc523549e 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -37,17 +37,10 @@ void * events_init_publisher_wrap(const char *event_source); */ void events_deinit_publisher_wrap(void *handle); -typedef struct param_wrap { +typedef struct param_C { const char *name; const char *val; -} param_wrap_t; - -typedef struct publish_data { - const char * tag; - - param_wrap_t * params; - int params_cnt; -} publish_data_t; +} param_C_t; /* * Publish an event. @@ -63,14 +56,10 @@ typedef struct publish_data { * == 0 -- Published successfully * < 0 -- Implies failure. Absoulte value is the error code */ -int event_publish_wrap(void *handle, const publish_data_t *data); +int event_publish_wrap(void *handle, const char *tag, + const param_C_t *params, size_t params_cnt); -typedef struct init_subs { - bool use_cache; - int recv_timeout; -} init_subs_t; - /* * Init subscriber * @@ -84,7 +73,7 @@ typedef struct init_subs { * < 0 -- Implies failure. Absoulte value is the error code */ -void *events_init_subscriber_wrap(const init_subs_t *init_data); +void *events_init_subscriber_wrap(bool use_cache, int recv_timeout); /* @@ -92,9 +81,6 @@ void *events_init_subscriber_wrap(const init_subs_t *init_data); * handle -- as provided be events_init_subscriber * */ -#define ARGS_KEY "key" -#define ARGS_MISSED_CNT "missed_cnt" - void events_deinit_subscriber_wrap(void *handle); /* @@ -111,19 +97,19 @@ void events_deinit_subscriber_wrap(void *handle); * < 0 - For all other failures */ -typedef struct event_receive_op { +typedef struct event_receive_op_C { /* Event as JSON string; c-string to help with C-binding for Go.*/ char *event_str; uint32_t event_sz; /* Sizeof event string */ uint32_t missed_cnt; /* missed count */ - uint64_t publish_epoch; /* Epoch timepoint of publish */ + uint64_t publish_epoch_ms; /* Epoch timepoint of publish */ -} event_receive_op_t; +} event_receive_op_C_t; -int event_receive_wrap(void *handle, event_receive_op_t *evt); +int event_receive_wrap(void *handle, event_receive_op_C_t *evt); /* * Set SWSS log priority diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 628c7bca8..b9345c95e 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -193,13 +193,7 @@ void do_test_publish(bool wrap) thread thr_sub(&run_sub); if (wrap) { - string json_str; - nlohmann::json obj = nlohmann::json::object(); - - obj[ARGS_SOURCE] = evt_source0; - - json_str = obj.dump(); - h = events_init_publisher_wrap(json_str.c_str()); + h = events_init_publisher_wrap(evt_source0.c_str()); } else { h = events_init_publisher(evt_source0); @@ -210,19 +204,17 @@ void do_test_publish(bool wrap) this_thread::sleep_for(chrono::milliseconds(300)); if (wrap) { - string json_str; - nlohmann::json obj = nlohmann::json::object(); - nlohmann::json obj_params = nlohmann::json::object(); + param_C_t params_list[params0.size()]; + param_C_t *params_ptr = params_list; + /* fill up list of params with bare pointers */ for (it_param = params0.begin(); it_param != params0.end(); ++it_param) { - obj_params[it_param->first] = it_param->second; + params_ptr->name = it_param->first.c_str(); + params_ptr->val = it_param->second.c_str(); + ++params_ptr; } - obj[ARGS_PARAMS] = obj_params; - obj[ARGS_TAG] = evt_tag0; - - json_str = obj.dump(); - - EXPECT_EQ(0, event_publish_wrap(h, json_str.c_str())); + EXPECT_EQ(0, event_publish_wrap(h, evt_tag0.c_str(), + params_list, params0.size())); } else { EXPECT_EQ(0, event_publish(h, evt_tag0, ¶ms0)); @@ -322,7 +314,7 @@ typedef struct { string rid; string seq; event_params_t params; - int missed_cnt; + uint32_t missed_cnt; } test_data_t; internal_event_t create_ev(const test_data_t &data) @@ -607,41 +599,36 @@ void do_test_subscribe(bool wrap) for(i=0; true; ++i) { string exp_key; event_receive_op_t evt; - string key; - event_params_t params; + int rc; if (wrap) { - char event_str[1024]; + char buff[1024]; + event_receive_op_C_t evtc; - int rc = event_receive_wrap(hsub, event_str, sizeof(event_str)); - EXPECT_LT(rc, sizeof(event_str)); + evtc.event_str = buff; + evtc.event_sz = ARRAY_SIZE(buff); - if (rc != 0) { - evt.from_json(event_str); - } - else if (rc == 0) { - evt.rc = EAGAIN; - } - else { - evt.rc = rc; + int rc = event_receive_wrap(hsub, &evtc); + if (rc == 0) { + evt.missed_cnt = evtc.missed_cnt; + evt.publish_epoch_ms = evtc.publish_epoch_ms; + rc = convert_from_json(evtc.event_str, evt.key, evt.params); } } else { - evt = event_receive(hsub); + rc = event_receive(hsub, evt); } - if (evt.rc != 0) { - EXPECT_EQ(EAGAIN, evt.rc); + if (rc != 0) { + EXPECT_EQ(EAGAIN, rc); break; } - evt.parse_event(key, params); - - EXPECT_EQ(ldata[i].params, params); + EXPECT_EQ(ldata[i].params, evt.params); exp_key = ldata[i].source + ":" + ldata[i].tag; - EXPECT_EQ(exp_key, key); + EXPECT_EQ(exp_key, evt.key); EXPECT_EQ(ldata[i].missed_cnt, evt.missed_cnt); From 00fa3a3ece40370cf092f41b79b88b0251917e90 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 22:49:02 +0000 Subject: [PATCH 68/97] compile fix --- common/events.cpp | 17 ++++++++++++++++- common/events.h | 4 ++++ common/events_pi.h | 4 +++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 0c5d53631..fc53949c1 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -561,6 +561,21 @@ event_receive(event_handle_t handle, event_receive_op_t &evt) return rc; } +int +event_receive_json(event_handle_t handle, string &event_str, + uint32_t &missed_cnt, uint64_t &publish_epoch) +{ + int rc = -1; + + EventSubscriber_ptr_t psubs = EventSubscriber::get_instance(handle); + RET_ON_ERR(psubs != NULL, "Invalid handle %p", handle); + + rc = psubs->event_receive(event_str, missed_cnt, publish_epoch); +out: + return rc; +} + + void * events_init_publisher_wrap(const char *event_source) { @@ -642,7 +657,7 @@ events_deinit_subscriber_wrap(void *handle) int -event_receive_wrap(void *handle, event_receive_op_t *evt) +event_receive_wrap(void *handle, event_receive_op_C_t *evt) { int rc = -1; diff --git a/common/events.h b/common/events.h index e1a2cc47b..9539ae90e 100644 --- a/common/events.h +++ b/common/events.h @@ -188,5 +188,9 @@ typedef struct { */ int event_receive(event_handle_t handle, event_receive_op_t &evt); +/* To receive as JSON */ +int event_receive_json(event_handle_t handle, std::string &evt, + uint32_t &missed_cnt, uint64_t &publish_epoch_ms); + #endif /* !_EVENTS_H */ diff --git a/common/events_pi.h b/common/events_pi.h index f241cb613..73bfee826 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -17,6 +17,7 @@ #include "events.h" #include "events_common.h" #include "events_service.h" +#include "events_wrap.h" using namespace std; @@ -103,6 +104,8 @@ class EventSubscriber : public events_base int event_receive(event_receive_op_t &); int event_receive(event_receive_op_C_t &); + int event_receive(string &event_str, uint32_t &missed, uint64_t &pub_ms); + private: EventSubscriber(); @@ -110,7 +113,6 @@ class EventSubscriber : public events_base int recv_timeout= -1, const event_subscribe_sources_t *subs_sources=NULL); - int event_receive(string &event_str, uint32_t &missed, uint64_t &pub_ms); void *m_zmq_ctx; void *m_socket; From 948ae40075ee275e612d184b6c1f9407d5413ada Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 22:56:33 +0000 Subject: [PATCH 69/97] compile fix --- common/events.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index fc53949c1..06480f6cf 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -257,7 +257,7 @@ EventSubscriber::get_instance(event_handle_t handle) ret = s_subscriber; out: - return rc; + return ret; } EventSubscriber::EventSubscriber(): m_zmq_ctx(NULL), m_socket(NULL), @@ -415,10 +415,10 @@ EventSubscriber::event_receive(event_receive_op_C_t &op) rc = -1; RET_ON_ERR(event_str.size() < op.event_sz, - "Event sz (%u) is too large for buffer sz=%u", + "Event sz (%lu) is too large for buffer sz=%u", event_str.size(), op.event_sz); - strncpy(op.event_str, event_str, op.event_sz); + strncpy(op.event_str, event_str.c_str(), op.event_sz); rc = 0; out: return rc; @@ -604,7 +604,7 @@ event_publish_wrap(void *handle, const char *tag_ptr, event_params_t params; if ((tag_ptr == NULL) || (*tag_ptr == 0) || - ((params_cnt != 0) && (params == NULL))) { + ((params_cnt != 0) && (params_ptr == NULL))) { SWSS_LOG_ERROR("event_publish_wrap: missing required args"); return -1; } From 96945ebe1676802c96830e8e7ebaa3a2ee131d57 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 23:01:10 +0000 Subject: [PATCH 70/97] compile fix --- common/events.cpp | 4 ++-- common/events_wrap.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 06480f6cf..a779de3c9 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -598,7 +598,7 @@ events_deinit_publisher_wrap(void *handle) int event_publish_wrap(void *handle, const char *tag_ptr, - const param_C_t *params_ptr, size_t params_cnt) + const param_C_t *params_ptr, uint32_t params_cnt) { string tag; event_params_t params; @@ -613,7 +613,7 @@ event_publish_wrap(void *handle, const char *tag_ptr, handle, tag_ptr, params_cnt); tag = string(tag_ptr); - for (size_t i=0; iname == NULL) || (*params_ptr->name == 0) || (params_ptr->val == NULL) || (*params_ptr->val == 0)) { SWSS_LOG_ERROR("event_publish_wrap: Missing param key/val"); diff --git a/common/events_wrap.h b/common/events_wrap.h index fc523549e..a8f15a2e4 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -57,7 +57,7 @@ typedef struct param_C { * < 0 -- Implies failure. Absoulte value is the error code */ int event_publish_wrap(void *handle, const char *tag, - const param_C_t *params, size_t params_cnt); + const param_C_t *params, uint32_t params_cnt); /* From a6d38ad6abc29d3ad9500d36de3ff6bf81d9f89a Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 23:08:33 +0000 Subject: [PATCH 71/97] compile fix --- common/events.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index a779de3c9..cbd6cfba2 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -626,18 +626,10 @@ event_publish_wrap(void *handle, const char *tag_ptr, } void * -events_init_subscriber_wrap(const init_subs_t *init_data) +events_init_subscriber_wrap(bool use_cache, int recv_timeout) { - bool use_cache = false; - int recv_timeout = -1; - event_subscribe_sources_t sources; void *handle = NULL; - if (init_data != NULL) { - use_cache = init_data->use_cache; - recv_timeout = init_data->recv_timeout; - } - SWSS_LOG_DEBUG("events_init_subsriber_wrap: use_cache=%d timeout=%d", use_cache, recv_timeout); @@ -660,10 +652,11 @@ int event_receive_wrap(void *handle, event_receive_op_C_t *evt) { int rc = -1; + EventSubscriber_ptr_t psubs; RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); - EventSubscriber_ptr_t psubs = EventSubscriber::get_instance(handle); + psubs = EventSubscriber::get_instance(handle); RET_ON_ERR(psubs != NULL, "Invalid handle %p", handle); rc = psubs->event_receive(*evt); From f07adc4b2da92dcbe5136b5038cc02552659df44 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 23:09:08 +0000 Subject: [PATCH 72/97] compile fix --- common/events.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index cbd6cfba2..97d772f99 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -628,12 +628,10 @@ event_publish_wrap(void *handle, const char *tag_ptr, void * events_init_subscriber_wrap(bool use_cache, int recv_timeout) { - void *handle = NULL; - SWSS_LOG_DEBUG("events_init_subsriber_wrap: use_cache=%d timeout=%d", use_cache, recv_timeout); - handle = events_init_subscriber(use_cache, recv_timeout); + void *handle = events_init_subscriber(use_cache, recv_timeout); SWSS_LOG_DEBUG("events_init_subscriber_wrap: handle=%p", handle); return handle; } From c3f06ccb1d5a196155b2de1019cf4a803823c586 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 23:20:54 +0000 Subject: [PATCH 73/97] compile fix --- tests/events_ut.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index b9345c95e..097ed56c9 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -545,12 +545,7 @@ void do_test_subscribe(bool wrap) thread thr_pub(&run_pub); if (wrap) { - nlohmann::json obj = nlohmann::json::object(); - - obj[ARGS_USE_CACHE] = true; - - string jstr(obj.dump()); - hsub = events_init_subscriber_wrap(jstr.c_str()); + hsub = events_init_subscriber_wrap(true, -1); } else { hsub = events_init_subscriber(true); @@ -581,12 +576,7 @@ void do_test_subscribe(bool wrap) /* We publish all events ahead of receive, so set a timeout */ if (wrap) { - nlohmann::json obj = nlohmann::json::object(); - - obj[ARGS_USE_CACHE] = true; - obj[ARGS_RECV_TIMEOUT] = 100; - string jstr(obj.dump()); - hsub = events_init_subscriber_wrap(jstr.c_str()); + hsub = events_init_subscriber_wrap(true, 100); } else { hsub = events_init_subscriber(true, 100); @@ -608,7 +598,7 @@ void do_test_subscribe(bool wrap) evtc.event_str = buff; evtc.event_sz = ARRAY_SIZE(buff); - int rc = event_receive_wrap(hsub, &evtc); + rc = event_receive_wrap(hsub, &evtc); if (rc == 0) { evt.missed_cnt = evtc.missed_cnt; evt.publish_epoch_ms = evtc.publish_epoch_ms; @@ -632,7 +622,7 @@ void do_test_subscribe(bool wrap) EXPECT_EQ(ldata[i].missed_cnt, evt.missed_cnt); - EXPECT_NE(0, evt.publish_epoch); + EXPECT_NE(0, evt.publish_epoch_ms); } EXPECT_EQ(i, (int)ARRAY_SIZE(ldata)); From 4d6f3f67a183619cb68ab5c8e544876a7ae93f6b Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 23:26:19 +0000 Subject: [PATCH 74/97] compile fix --- tests/events_ut.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 097ed56c9..994cc2413 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -214,7 +214,7 @@ void do_test_publish(bool wrap) ++params_ptr; } EXPECT_EQ(0, event_publish_wrap(h, evt_tag0.c_str(), - params_list, params0.size())); + params_list, (uint32_t)params0.size())); } else { EXPECT_EQ(0, event_publish(h, evt_tag0, ¶ms0)); From d3475cc2aaa74675a12716af9b3015ad64a3e114 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 23:34:05 +0000 Subject: [PATCH 75/97] compile fix --- tests/events_ut.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 994cc2413..31c34907f 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -204,14 +204,19 @@ void do_test_publish(bool wrap) this_thread::sleep_for(chrono::milliseconds(300)); if (wrap) { - param_C_t params_list[params0.size()]; + param_C_t params_list[10]; param_C_t *params_ptr = params_list; + int i = 0; /* fill up list of params with bare pointers */ for (it_param = params0.begin(); it_param != params0.end(); ++it_param) { params_ptr->name = it_param->first.c_str(); params_ptr->val = it_param->second.c_str(); ++params_ptr; + if (++i >= ARRAY_SIZE(params_list)) { + EXPECT_TRUE(false, "Check params list size"); + break; + } } EXPECT_EQ(0, event_publish_wrap(h, evt_tag0.c_str(), params_list, (uint32_t)params0.size())); From 4ee2050edd10ceb546d6ff9955afef88a76df7d2 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Tue, 26 Jul 2022 23:39:18 +0000 Subject: [PATCH 76/97] compile fix --- tests/events_ut.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 31c34907f..65079227e 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -213,8 +213,8 @@ void do_test_publish(bool wrap) params_ptr->name = it_param->first.c_str(); params_ptr->val = it_param->second.c_str(); ++params_ptr; - if (++i >= ARRAY_SIZE(params_list)) { - EXPECT_TRUE(false, "Check params list size"); + if (++i >= (int)ARRAY_SIZE(params_list)) { + EXPECT_TRUE(false); break; } } From 33cd34e9c44a49f909a719e91a4f88d505994e90 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Wed, 27 Jul 2022 16:28:30 +0000 Subject: [PATCH 77/97] compile fix --- common/events.cpp | 15 +++++++++------ common/events_pi.h | 1 + tests/events_ut.cpp | 27 ++++++++++++--------------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 97d772f99..beefff366 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -8,6 +8,7 @@ */ lst_publishers_t EventPublisher::s_publishers; +int EventPublisher::LINGER_TIMEOUT = 100; // In milliseconds event_handle_t EventPublisher::get_publisher(const string event_source) @@ -78,6 +79,9 @@ int EventPublisher::init(const string event_source) int rc = zmq_connect (sock, get_config(XSUB_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Publisher fails to connect %s", get_config(XSUB_END_KEY).c_str()); + rc = zmq_setsockopt (sock, ZMQ_LINGER, &LINGER_TIMEOUT, sizeof (LINGER_TIMEOUT)); + RET_ON_ERR(rc == 0, "Failed to ZMQ_LINGER to %d", LINGER_TIMEOUT); + /* * Event service could be down. So have a timeout. * @@ -485,13 +489,12 @@ EventSubscriber::event_receive(string &event_str, uint32_t &missed_cnt, } else { /* - * First message seen from this runtime id, implying - * all earlier messages are lost. + * First message seen from this runtime id. We can't imply + * all earlier messages are lost, as eventd could have been + * restarted and this publisher is long running. + * Hence skip. + * eventd going down should be seldom. */ - if (seq != 0) { - this_missed_cnt = seq - 1; - } - /* roll over is nearly impossible - 4GB events not seen */ /* May need to add new ID to track; Prune if needed */ if (m_track.size() > (MAX_PUBLISHERS_COUNT + 10)) { diff --git a/common/events_pi.h b/common/events_pi.h index 73bfee826..1e6524ba6 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -44,6 +44,7 @@ typedef map lst_publishers_t; class EventPublisher : public events_base { static lst_publishers_t s_publishers; + static int LINGER_TIMEOUT; public: virtual ~EventPublisher(); diff --git a/tests/events_ut.cpp b/tests/events_ut.cpp index 65079227e..007ca21dd 100644 --- a/tests/events_ut.cpp +++ b/tests/events_ut.cpp @@ -126,15 +126,11 @@ parse_read_evt(string &source, internal_event_t &evt, } EXPECT_FALSE(source.empty()); - EXPECT_EQ(3, evt.size()); + EXPECT_EQ(4, evt.size()); for (const auto e: evt) { if (e.first == EVENT_STR_DATA) { - map_str_str_t m; - EXPECT_EQ(0, deserialize(e.second, m)); - EXPECT_EQ(1, m.size()); - key = m.begin()->first; - EXPECT_EQ(0, deserialize(m.begin()->second, params)); + EXPECT_EQ(0, convert_from_json(e.second, key, params)); // cout << "EVENT_STR_DATA: " << e.second << "\n"; } else if (e.first == EVENT_RUNTIME_ID) { @@ -146,6 +142,14 @@ parse_read_evt(string &source, internal_event_t &evt, ss >> seq; // cout << "EVENT_SEQUENCE: " << seq << "\n"; } + else if (e.first == EVENT_EPOCH) { + istringstream iss(e.second); + uint64_t val; + + iss >> val; + // cout << "EVENT_EPOCH: " << seq << "\n"; + EXPECT_NE(val, 0); + } else { EXPECT_FALSE(true); } @@ -326,15 +330,8 @@ internal_event_t create_ev(const test_data_t &data) { internal_event_t event_data; - { - string param_str; - - EXPECT_EQ(0, serialize(data.params, param_str)); - - map_str_str_t event_str_map = { { data.source + ":" + data.tag, param_str}}; - - EXPECT_EQ(0, serialize(event_str_map, event_data[EVENT_STR_DATA])); - } + event_data[EVENT_STR_DATA] = + convert_to_json(data.source + ":" + data.tag, data.params); event_data[EVENT_RUNTIME_ID] = data.rid; event_data[EVENT_SEQUENCE] = data.seq; From 972fa62b7661c9a51fbe1fe02cd108ac76060b6b Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 28 Jul 2022 15:07:20 +0000 Subject: [PATCH 78/97] compile fix --- common/events.cpp | 4 ++-- common/events.h | 2 +- common/events_pi.h | 2 +- common/events_wrap.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index beefff366..8e1e4d80a 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -136,7 +136,7 @@ EventPublisher::send_evt(const string str_data) (int)str_data.size(), EVENT_MAXSZ); } auto timepoint = system_clock::now(); - ss << duration_cast(timepoint.time_since_epoch()).count(); + ss << duration_cast(timepoint.time_since_epoch()).count(); event_data[EVENT_STR_DATA] = str_data; event_data[EVENT_RUNTIME_ID] = m_runtime_id; @@ -445,7 +445,7 @@ EventSubscriber::event_receive(event_receive_op_t &op) int EventSubscriber::event_receive(string &event_str, uint32_t &missed_cnt, - uint64_t &publish_epoch) + int64_t &publish_epoch) { int rc = 0; missed_cnt = 0; diff --git a/common/events.h b/common/events.h index 9539ae90e..bd90a25e7 100644 --- a/common/events.h +++ b/common/events.h @@ -162,7 +162,7 @@ typedef struct { std::string key; /* key */ event_params_t params; /* Params received */ uint32_t missed_cnt; /* missed count */ - uint64_t publish_epoch_ms; /* Epoch time in milliseconds */ + int64_t publish_epoch_ms; /* Epoch time in milliseconds */ } event_receive_op_t; /* diff --git a/common/events_pi.h b/common/events_pi.h index 1e6524ba6..22ff6f67e 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -105,7 +105,7 @@ class EventSubscriber : public events_base int event_receive(event_receive_op_t &); int event_receive(event_receive_op_C_t &); - int event_receive(string &event_str, uint32_t &missed, uint64_t &pub_ms); + int event_receive(string &event_str, uint32_t &missed, int64_t &pub_ms); private: EventSubscriber(); diff --git a/common/events_wrap.h b/common/events_wrap.h index a8f15a2e4..645025907 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -104,7 +104,7 @@ typedef struct event_receive_op_C { uint32_t missed_cnt; /* missed count */ - uint64_t publish_epoch_ms; /* Epoch timepoint of publish */ + int64_t publish_epoch_ms; /* Epoch timepoint of publish */ } event_receive_op_C_t; From 3ccb8241ce79b192323fe8fde4efab8e4b7bb748 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 28 Jul 2022 16:35:41 +0000 Subject: [PATCH 79/97] compile fix --- common/events.cpp | 2 +- common/events.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 8e1e4d80a..9efb0eb83 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -566,7 +566,7 @@ event_receive(event_handle_t handle, event_receive_op_t &evt) int event_receive_json(event_handle_t handle, string &event_str, - uint32_t &missed_cnt, uint64_t &publish_epoch) + uint32_t &missed_cnt, int64_t &publish_epoch) { int rc = -1; diff --git a/common/events.h b/common/events.h index bd90a25e7..e49d869fe 100644 --- a/common/events.h +++ b/common/events.h @@ -190,7 +190,7 @@ int event_receive(event_handle_t handle, event_receive_op_t &evt); /* To receive as JSON */ int event_receive_json(event_handle_t handle, std::string &evt, - uint32_t &missed_cnt, uint64_t &publish_epoch_ms); + uint32_t &missed_cnt, int64_t &publish_epoch_ms); #endif /* !_EVENTS_H */ From bb777f3e649be62487a3854a31903e61ac403dc6 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Fri, 29 Jul 2022 23:04:43 +0000 Subject: [PATCH 80/97] compile fix --- common/events_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/events_common.h b/common/events_common.h index 727a3603b..554c6bcfc 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -321,7 +321,7 @@ struct serialization else { /* override with zmq err */ rc = zmq_errno(); - RET_ON_ERR(false, "Failed to read part rc=%d", rc); + RET_ON_ERR(rc == 11, "Failed to read part rc=%d", rc); } out: zmq_msg_close(&msg); @@ -381,7 +381,7 @@ struct serialization */ rc2 = zmq_read_part(sock, 0, more, pt2); } - RET_ON_ERR(rc == 0, "Failed to read part1"); + RET_ON_ERR((rc == 0) || (rc == 11), "Failed to read part1"); if (rc2 != 0) { rc = rc2; RET_ON_ERR(false, "Failed to read part2"); From 13a7f5c3b120214a6e1c86c3a62ac1863f5e0edf Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Sat, 30 Jul 2022 18:14:42 +0000 Subject: [PATCH 81/97] compile fix --- common/events.cpp | 14 ++++++++++++-- common/events_common.h | 6 ++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 9efb0eb83..fd3ad5d5a 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -415,7 +415,12 @@ EventSubscriber::event_receive(event_receive_op_C_t &op) op.event_str, op.event_sz); rc = event_receive(event_str, op.missed_cnt, op.publish_epoch_ms); - RET_ON_ERR(rc == 0, "failed to receive event"); + if (rc != 0) { + if (rc != 11) { + SWSS_LOG_ERROR("failed to receive event"); + } + goto out; + } rc = -1; RET_ON_ERR(event_str.size() < op.event_sz, @@ -470,7 +475,12 @@ EventSubscriber::event_receive(string &event_str, uint32_t &missed_cnt, /* Read from SUBS channel */ string evt_source; rc = zmq_message_read(m_socket, 0, evt_source, event_data); - RET_ON_ERR(rc == 0, "Failed to read message from sock rc=%d", rc); + if (rc != 0) { + if (rc != 11) { + SWSS_LOG_ERROR("Failure to read message from sock rc=%d", rc); + } + goto out; + } } /* Find any missed events for this runtime ID */ diff --git a/common/events_common.h b/common/events_common.h index 554c6bcfc..9531ff9ad 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -321,7 +321,9 @@ struct serialization else { /* override with zmq err */ rc = zmq_errno(); - RET_ON_ERR(rc == 11, "Failed to read part rc=%d", rc); + if (rc != 11) { + SWSS_LOG_ERROR("Failure to read part rc=%d", rc); + } } out: zmq_msg_close(&msg); @@ -381,7 +383,7 @@ struct serialization */ rc2 = zmq_read_part(sock, 0, more, pt2); } - RET_ON_ERR((rc == 0) || (rc == 11), "Failed to read part1"); + RET_ON_ERR((rc == 0) || (rc == 11), "Failure to read part1"); if (rc2 != 0) { rc = rc2; RET_ON_ERR(false, "Failed to read part2"); From 07cff7e6d57155b4e901b4ccd77d02ab568fc024 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Sat, 30 Jul 2022 20:07:25 +0000 Subject: [PATCH 82/97] compile fix --- common/events.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index fd3ad5d5a..dc659569c 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -417,7 +417,7 @@ EventSubscriber::event_receive(event_receive_op_C_t &op) rc = event_receive(event_str, op.missed_cnt, op.publish_epoch_ms); if (rc != 0) { if (rc != 11) { - SWSS_LOG_ERROR("failed to receive event"); + SWSS_LOG_ERROR("failed to receive event. rc=%d", rc); } goto out; } @@ -440,7 +440,12 @@ EventSubscriber::event_receive(event_receive_op_t &op) int rc = -1; rc = event_receive(event_str, op.missed_cnt, op.publish_epoch_ms); - RET_ON_ERR(rc == 0, "failed to receive event"); + if (rc != 0) { + if (rc != 11) { + SWSS_LOG_ERROR("failed to receive event. rc=%d", rc); + } + goto out; + } rc = convert_from_json(event_str, op.key, op.params); RET_ON_ERR(rc == 0, "failed to parse %s", event_str.c_str()); From aa9c3fe84eaf58b1011fe27b17e162bd82fd0bbe Mon Sep 17 00:00:00 2001 From: Zain Budhwani <99770260+zbud-msft@users.noreply.github.com> Date: Tue, 2 Aug 2022 14:09:33 -0700 Subject: [PATCH 83/97] Add libzmq5 as dependency for ubuntu-20.04 build (#7) Co-authored-by: Ubuntu --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 43ca7391e..6fec39a10 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -62,7 +62,7 @@ stages: sudo apt-get update sudo apt-get install -y make libtool m4 autoconf dh-exec debhelper cmake pkg-config \ libhiredis-dev libnl-3-dev libnl-genl-3-dev libnl-route-3-dev libnl-nf-3-dev swig3.0 \ - libpython2.7-dev libboost-dev libboost1.71-dev + libpython2.7-dev libboost-dev libboost1.71-dev libzmq5 sudo apt-get install -y sudo sudo apt-get install -y redis-server redis-tools sudo apt-get install -y python3-pip From d81441bf13af7623bfeab3c88e2f5a7df3f56e48 Mon Sep 17 00:00:00 2001 From: Zain Budhwani <99770260+zbud-msft@users.noreply.github.com> Date: Tue, 2 Aug 2022 15:01:31 -0700 Subject: [PATCH 84/97] Modify azp (#8) * Add libzmq5 as dependency for ubuntu-20.04 build * Add libzmq3-dev dependency to build script Co-authored-by: Ubuntu --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6fec39a10..6e499612c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -62,7 +62,7 @@ stages: sudo apt-get update sudo apt-get install -y make libtool m4 autoconf dh-exec debhelper cmake pkg-config \ libhiredis-dev libnl-3-dev libnl-genl-3-dev libnl-route-3-dev libnl-nf-3-dev swig3.0 \ - libpython2.7-dev libboost-dev libboost1.71-dev libzmq5 + libpython2.7-dev libboost-dev libboost1.71-dev libzmq5 libzmq3-dev sudo apt-get install -y sudo sudo apt-get install -y redis-server redis-tools sudo apt-get install -y python3-pip From 6b79a20e7248d317ce067a83429f0a36ee427021 Mon Sep 17 00:00:00 2001 From: Zain Budhwani <99770260+zbud-msft@users.noreply.github.com> Date: Tue, 2 Aug 2022 15:53:17 -0700 Subject: [PATCH 85/97] Modify azp (#9) * Add libzmq5 as dependency for ubuntu-20.04 build * Add libzmq3-dev dependency to build script * Add uuid-dev and libboost-serialization-dev dependencies Co-authored-by: Ubuntu --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6e499612c..200426677 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -62,7 +62,7 @@ stages: sudo apt-get update sudo apt-get install -y make libtool m4 autoconf dh-exec debhelper cmake pkg-config \ libhiredis-dev libnl-3-dev libnl-genl-3-dev libnl-route-3-dev libnl-nf-3-dev swig3.0 \ - libpython2.7-dev libboost-dev libboost1.71-dev libzmq5 libzmq3-dev + libpython2.7-dev libboost-dev libboost1.71-dev libboost-serialization-dev uuid-dev libzmq5 libzmq3-dev sudo apt-get install -y sudo sudo apt-get install -y redis-server redis-tools sudo apt-get install -y python3-pip From 40f06656599b9d57bef8e86926d9f850170d48c9 Mon Sep 17 00:00:00 2001 From: Zain Budhwani <99770260+zbud-msft@users.noreply.github.com> Date: Tue, 2 Aug 2022 17:08:55 -0700 Subject: [PATCH 86/97] Modify azp (#10) * Add libzmq5 as dependency for ubuntu-20.04 build * Add libzmq3-dev dependency to build script * Add uuid-dev and libboost-serialization-dev dependencies * Add dependencies for bazel build Co-authored-by: Ubuntu --- BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD b/BUILD index d81415343..9b4fb653b 100644 --- a/BUILD +++ b/BUILD @@ -15,7 +15,7 @@ cc_library( includes = [ "common", ], - linkopts = ["-lpthread -lhiredis -lnl-genl-3 -lnl-nf-3 -lnl-route-3 -lnl-3"], + linkopts = ["-lpthread -lhiredis -lnl-genl-3 -lnl-nf-3 -lnl-route-3 -lnl-3 -lzmq -lboost_serialization -luuid"], visibility = ["//visibility:public"], ) From fe863a751358607ff3616359ccedfc7ceee98da9 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 03:55:02 +0000 Subject: [PATCH 87/97] compile errors --- common/Makefile.am | 6 ++++-- common/events.cpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index b47cfd217..3bf52a084 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -72,8 +72,10 @@ libswsscommon_la_SOURCES = \ countertable.cpp \ redisutility.cpp -libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) -libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS) +CMN_FLAGS = -Wno-psabi -Wall -Wextra -pedantic + +libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) $(CMN_FLAGS) +libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS) $(CMN_FLAGS) libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid swssloglevel_SOURCES = loglevel.cpp diff --git a/common/events.cpp b/common/events.cpp index dc659569c..347fb784e 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -424,8 +424,8 @@ EventSubscriber::event_receive(event_receive_op_C_t &op) rc = -1; RET_ON_ERR(event_str.size() < op.event_sz, - "Event sz (%lu) is too large for buffer sz=%u", - event_str.size(), op.event_sz); + "Event sz (%d) is too large for buffer sz=%u", + (int)event_str.size(), op.event_sz); strncpy(op.event_str, event_str.c_str(), op.event_sz); rc = 0; From 3c8e1f06cc12658fe7d342c67c1336daf63cfb20 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 03:55:50 +0000 Subject: [PATCH 88/97] compile errors --- common/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/common/Makefile.am b/common/Makefile.am index 3bf52a084..81130d648 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -72,6 +72,7 @@ libswsscommon_la_SOURCES = \ countertable.cpp \ redisutility.cpp +# Refer: https://github.com/nlohmann/json/issues/1861 CMN_FLAGS = -Wno-psabi -Wall -Wextra -pedantic libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) $(CMN_FLAGS) From 36e18f7321b74a7b17f8a89ac5ddd2d0961229f1 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 15:08:23 +0000 Subject: [PATCH 89/97] Compile error from Ubuntu --- common/events_common.h | 6 +++--- common/events_service.cpp | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common/events_common.h b/common/events_common.h index 9531ff9ad..d83d1f62a 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -383,14 +383,14 @@ struct serialization */ rc2 = zmq_read_part(sock, 0, more, pt2); } - RET_ON_ERR((rc == 0) || (rc == 11), "Failure to read part1"); + RET_ON_ERR((rc == 0) || (rc == 11), "Failure to read part1 rc=%d", rc); if (rc2 != 0) { rc = rc2; - RET_ON_ERR(false, "Failed to read part2"); + RET_ON_ERR(false, "Failed to read part2 rc=%d", rc); } if (more) { rc = -1; - RET_ON_ERR(false, "Don't expect more than 2 parts"); + RET_ON_ERR(false, "Don't expect more than 2 parts, rc=%d", rc); } out: return rc; diff --git a/common/events_service.cpp b/common/events_service.cpp index 4c14e4d5d..b6ee8056c 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -33,7 +33,7 @@ event_service::init_client(void *zmq_ctx, int block_ms) int rc = -1; void *sock = zmq_socket (zmq_ctx, ZMQ_REQ); - RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REQ socket"); + RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REQ socket rc=%d", rc); rc = zmq_connect (sock, get_config(REQ_REP_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY).c_str()); @@ -58,7 +58,7 @@ event_service::init_server(void *zmq_ctx, int block_ms) int rc = -1; void *sock = zmq_socket (zmq_ctx, ZMQ_REP); - RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REP socket"); + RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REP socket rc=%d", rc); rc = zmq_bind (sock, get_config(REQ_REP_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Failed to bind to %s", get_config(REQ_REP_END_KEY).c_str()); @@ -95,7 +95,7 @@ event_service::echo_receive(string &outs) int code; int rc = channel_read(code, l); - RET_ON_ERR(rc == 0, "failing to read echo"); + RET_ON_ERR(rc == 0, "failing to read echo rc=%d", rc); RET_ON_ERR (code == 0, "echo receive resp %d not 0", code); RET_ON_ERR (l.size() == 1, "echo received resp size %d is not 1", @@ -125,7 +125,7 @@ event_service::cache_start(const event_serialized_lst_t &lst) int rc; RET_ON_ERR((rc = send_recv(EVENT_CACHE_START, &lst)) == 0, - "Failed to send cache start"); + "Failed to send cache start rc=%d", rc); out: return rc; } @@ -137,7 +137,7 @@ event_service::cache_stop() int rc; RET_ON_ERR((rc = send_recv(EVENT_CACHE_STOP)) == 0, - "Failed to send cache stop"); + "Failed to send cache stop rc=%d", rc); out: return rc; } @@ -149,7 +149,7 @@ event_service::cache_read(event_serialized_lst_t &lst) int rc; RET_ON_ERR((rc = send_recv(EVENT_CACHE_READ, NULL, &lst)) == 0, - "Failed to send cache read"); + "Failed to send cache read rc=%d", rc); out: return rc; } From fc65a9141e90269a776febcfaf96bdf20ff89345 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 15:24:30 +0000 Subject: [PATCH 90/97] drop unused macro --- common/logger.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/common/logger.h b/common/logger.h index 79fdec47f..3bef58e98 100644 --- a/common/logger.h +++ b/common/logger.h @@ -31,12 +31,6 @@ void err_exit(const char *fn, int ln, int e, const char *fmt, ...) #endif ; -#define ABORT_IF_NOT(x, fmt, args...) \ - if (!(x)) { \ - int e = errno; \ - err_exit(__FUNCTION__, __LINE__, e, (fmt), ##args); \ - } - #ifdef __GNUC__ # define ATTRIBUTE_NORTEURN __attribute__ ((noreturn)) #else From 0ff6c102d8f89870b57b806519315d80fc9675ce Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 15:42:02 +0000 Subject: [PATCH 91/97] compile fix --- common/events.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 347fb784e..65ccd9b47 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -87,7 +87,7 @@ int EventPublisher::init(const string event_source) * */ rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MS_PUB); - RET_ON_ERR (rc == 0, "Failed to init event service"); + RET_ON_ERR (rc == 0, "Failed to init event service rc=%d", rc); /* * REQ socket is connected and a message is sent & received, more to @@ -98,7 +98,7 @@ int EventPublisher::init(const string event_source) * the first event is published, the echo response will be available locally. */ rc = m_event_service.echo_send("hello"); - RET_ON_ERR (rc == 0, "Failed to echo send in event service"); + RET_ON_ERR (rc == 0, "Failed to echo send in event service rc=%d", rc); m_event_source = event_source; @@ -232,7 +232,7 @@ EventSubscriber::get_subscriber(bool use_cache, int recv_timeout, EventSubscriber_ptr_t sub(new EventSubscriber()); RET_ON_ERR(sub->init(use_cache, recv_timeout, sources) == 0, - "Failed to init subscriber"); + "Failed to init subscriber recv_timeout=%d", recv_timeout); s_subscriber = sub; } @@ -257,7 +257,7 @@ EventSubscriber::get_instance(event_handle_t handle) EventSubscriber_ptr_t ret; RET_ON_ERR ((handle == s_subscriber.get()) && (s_subscriber != NULL), - "Invalid handle for get_instance"); + "Invalid handle for get_instance handle=%p", handle); ret = s_subscriber; out: @@ -287,7 +287,7 @@ EventSubscriber::~EventSubscriber() event_serialized_lst_t events; rc = m_event_service.cache_init(); - RET_ON_ERR(rc == 0, "Failed to init the cache"); + RET_ON_ERR(rc == 0, "Failed to init the cache rc=%d", rc); /* Shadow the cache init request, as it is async */ m_event_service.send_recv(EVENT_ECHO); @@ -319,7 +319,7 @@ EventSubscriber::~EventSubscriber() /* Start cache service with locally read events as initial stock */ RET_ON_ERR(m_event_service.cache_start(events) == 0, - "Failed to send cache start"); + "Failed to send cache start rc=%d", rc); m_event_service.close_service(); } out: @@ -351,12 +351,12 @@ EventSubscriber::init(bool use_cache, int recv_timeout, if ((subs_sources == NULL) || (subs_sources->empty())) { rc = zmq_setsockopt(sock, ZMQ_SUBSCRIBE, "", 0); - RET_ON_ERR(rc == 0, "Fails to set option"); + RET_ON_ERR(rc == 0, "Fails to set option rc=%d", rc); } else { for (const auto e: *subs_sources) { rc = zmq_setsockopt(sock, ZMQ_SUBSCRIBE, e.c_str(), e.size()); - RET_ON_ERR(rc == 0, "Fails to set option"); + RET_ON_ERR(rc == 0, "Fails to set option rc=%d", rc); } } @@ -367,7 +367,7 @@ EventSubscriber::init(bool use_cache, int recv_timeout, if (use_cache) { rc = m_event_service.init_client(m_zmq_ctx, EVENTS_SERVICE_TIMEOUT_MS_SUB); - RET_ON_ERR(rc == 0, "Fails to init the service"); + RET_ON_ERR(rc == 0, "Fails to init the service rc=%d", rc); if (m_event_service.cache_stop() == 0) { // Stopped an active cache @@ -473,7 +473,7 @@ EventSubscriber::event_receive(string &event_str, uint32_t &missed_cnt, event_serialized_lst_t::iterator it = m_from_cache.begin(); rc = deserialize(*it, event_data); m_from_cache.erase(it); - RET_ON_ERR(rc == 0, "Failed to deserialize message from cache"); + RET_ON_ERR(rc == 0, "Failed to deserialize message from cache rc=%d", rc); } else { @@ -670,7 +670,7 @@ event_receive_wrap(void *handle, event_receive_op_C_t *evt) int rc = -1; EventSubscriber_ptr_t psubs; - RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event"); + RET_ON_ERR(evt != NULL, "Require non null evt pointer to receive event rc=%d", rc); psubs = EventSubscriber::get_instance(handle); RET_ON_ERR(psubs != NULL, "Invalid handle %p", handle); From 4d24e6ff5058edd31352b21adcfd98129b6520a7 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 15:49:05 +0000 Subject: [PATCH 92/97] compile fix --- common/events.cpp | 7 ++++--- common/logger.cpp | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 65ccd9b47..034864de2 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -266,7 +266,7 @@ EventSubscriber::get_instance(event_handle_t handle) EventSubscriber::EventSubscriber(): m_zmq_ctx(NULL), m_socket(NULL), m_cache_read(false) -{}; +{} EventSubscriber::~EventSubscriber() @@ -623,7 +623,8 @@ event_publish_wrap(void *handle, const char *tag_ptr, if ((tag_ptr == NULL) || (*tag_ptr == 0) || ((params_cnt != 0) && (params_ptr == NULL))) { - SWSS_LOG_ERROR("event_publish_wrap: missing required args"); + SWSS_LOG_ERROR("event_publish_wrap: missing required args params_cnt=%u", + params_cnt); return -1; } @@ -634,7 +635,7 @@ event_publish_wrap(void *handle, const char *tag_ptr, for (uint32_t i=0; iname == NULL) || (*params_ptr->name == 0) || (params_ptr->val == NULL) || (*params_ptr->val == 0)) { - SWSS_LOG_ERROR("event_publish_wrap: Missing param key/val"); + SWSS_LOG_ERROR("event_publish_wrap: Missing param key/val i=%u", i); return -1; } params[params_ptr->name] = params_ptr->val; diff --git a/common/logger.cpp b/common/logger.cpp index b27cbed93..f63294829 100644 --- a/common/logger.cpp +++ b/common/logger.cpp @@ -78,7 +78,7 @@ void Logger::swssPrioNotify(const std::string& component, const std::string& pri if (priorityStringMap.find(prioStr) == priorityStringMap.end()) { - SWSS_LOG_ERROR("Invalid loglevel. Setting to NOTICE."); + SWSS_LOG_ERROR("Invalid loglevel. Setting to NOTICE. %s", prioStr.c_str()); logger.m_minPrio = SWSS_NOTICE; } else @@ -99,7 +99,7 @@ void Logger::swssOutputNotify(const std::string& component, const std::string& o if (outputStringMap.find(outputStr) == outputStringMap.end()) { - SWSS_LOG_ERROR("Invalid logoutput. Setting to SYSLOG."); + SWSS_LOG_ERROR("Invalid logoutput. Setting to SYSLOG. %s", outputStr.c_str()); logger.m_output = SWSS_SYSLOG; } else From e3db7b8313172c31439d11ea397fb1b056770920 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 16:07:55 +0000 Subject: [PATCH 93/97] remove pedantic --- common/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/Makefile.am b/common/Makefile.am index 81130d648..e43b79dd2 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -73,7 +73,7 @@ libswsscommon_la_SOURCES = \ redisutility.cpp # Refer: https://github.com/nlohmann/json/issues/1861 -CMN_FLAGS = -Wno-psabi -Wall -Wextra -pedantic +CMN_FLAGS = -Wno-psabi -Wall -Wextra libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) $(CMN_FLAGS) libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS) $(CMN_FLAGS) From 2dab4e8721c12c00d0b085c327b7edb4bd09a977 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 16:16:51 +0000 Subject: [PATCH 94/97] restored ABORT_IF_NOT --- common/logger.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/logger.h b/common/logger.h index 3bef58e98..79fdec47f 100644 --- a/common/logger.h +++ b/common/logger.h @@ -31,6 +31,12 @@ void err_exit(const char *fn, int ln, int e, const char *fmt, ...) #endif ; +#define ABORT_IF_NOT(x, fmt, args...) \ + if (!(x)) { \ + int e = errno; \ + err_exit(__FUNCTION__, __LINE__, e, (fmt), ##args); \ + } + #ifdef __GNUC__ # define ATTRIBUTE_NORTEURN __attribute__ ((noreturn)) #else From 7546a87965f7672eb950a0204b16cb75fb6ee2b8 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Thu, 4 Aug 2022 18:05:39 +0000 Subject: [PATCH 95/97] revert flag add --- common/Makefile.am | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index e43b79dd2..b47cfd217 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -72,11 +72,8 @@ libswsscommon_la_SOURCES = \ countertable.cpp \ redisutility.cpp -# Refer: https://github.com/nlohmann/json/issues/1861 -CMN_FLAGS = -Wno-psabi -Wall -Wextra - -libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) $(CMN_FLAGS) -libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS) $(CMN_FLAGS) +libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) +libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS) libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid swssloglevel_SOURCES = loglevel.cpp From 6de256605b4b4948647437a3d478a7ba15344284 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Sat, 6 Aug 2022 02:27:13 +0000 Subject: [PATCH 96/97] comments correction --- common/events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/events.h b/common/events.h index e49d869fe..a4a32a0a3 100644 --- a/common/events.h +++ b/common/events.h @@ -27,7 +27,7 @@ typedef void* event_handle_t; * * NOTE: * The initialization occurs asynchronously. - * Any event published before init is complete, is blocked until the init + * Any event published before init is complete, is blocked until the init. * is complete. Hence recommend, do the init as soon as the process starts. * * Input: From 7fd1e4a9687e552b1ac5af84a84941c67a8ea019 Mon Sep 17 00:00:00 2001 From: Renuka Manavalan Date: Mon, 8 Aug 2022 17:44:00 +0000 Subject: [PATCH 97/97] Log every published event --- common/events.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/common/events.cpp b/common/events.cpp index 034864de2..c2a955b0a 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -191,12 +191,11 @@ EventPublisher::publish(const string tag, const event_params_t *params) } str_data = convert_to_json(m_event_source + ":" + tag, *params); + SWSS_LOG_INFO("EVENT_PUBLISHED: %s", str_data.c_str()); + rc = send_evt(str_data); RET_ON_ERR(rc == 0, "failed to send event str[%d]= %s", (int)str_data.size(), str_data.substr(0, 20).c_str()); - - SWSS_LOG_INFO("EVENT_PUBLISHED: %s", str_data.substr(0, 80).c_str()); - out: return rc; }