-
Notifications
You must be signed in to change notification settings - Fork 690
Add cfgOrch class #355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add cfgOrch class #355
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| #include "cfgorch.h" | ||
| #include "logger.h" | ||
| #include "subscriberstatetable.h" | ||
|
|
||
| using namespace swss; | ||
|
|
||
| CfgOrch::CfgOrch(DBConnector *db, string tableName) : | ||
| m_db(db) | ||
| { | ||
| Consumer consumer(new SubscriberStateTable(m_db, tableName)); | ||
| m_consumerMap.insert(ConsumerMapPair(tableName, consumer)); | ||
| } | ||
|
|
||
| CfgOrch::CfgOrch(DBConnector *db, vector<string> &tableNames) : | ||
| m_db(db) | ||
| { | ||
| for(auto it : tableNames) | ||
| { | ||
| Consumer consumer(new SubscriberStateTable(m_db, it)); | ||
| m_consumerMap.insert(ConsumerMapPair(it, consumer)); | ||
| } | ||
| } | ||
|
|
||
| CfgOrch::~CfgOrch() | ||
| { | ||
| for(auto &it : m_consumerMap) | ||
| delete it.second.m_consumer; | ||
| } | ||
|
|
||
| vector<Selectable *> CfgOrch::getSelectables() | ||
| { | ||
| vector<Selectable *> selectables; | ||
| for(auto it : m_consumerMap) { | ||
| selectables.push_back(it.second.m_consumer); | ||
| } | ||
| return selectables; | ||
| } | ||
|
|
||
| bool CfgOrch::hasSelectable(TableConsumable *selectable) const | ||
| { | ||
| for(auto it : m_consumerMap) { | ||
| if (it.second.m_consumer == selectable) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| bool CfgOrch::syncCfgDB(string tableName, Table &tableConsumer) | ||
| { | ||
| SWSS_LOG_ENTER(); | ||
|
|
||
| auto consumer_it = m_consumerMap.find(tableName); | ||
| if (consumer_it == m_consumerMap.end()) | ||
| { | ||
| SWSS_LOG_ERROR("Unrecognized tableName:%s\n", tableName.c_str()); | ||
| return false; | ||
| } | ||
| Consumer& consumer = consumer_it->second; | ||
|
|
||
| vector<KeyOpFieldsValuesTuple> tuples; | ||
|
|
||
| tableConsumer.getTableContent(tuples); | ||
| for (auto tuple : tuples) | ||
| { | ||
| string key = kfvKey(tuple); | ||
| /* Directly put it into consumer.m_toSync map */ | ||
| if (consumer.m_toSync.find(key) == consumer.m_toSync.end()) | ||
| { | ||
| consumer.m_toSync[key] = make_tuple(key, SET_COMMAND, kfvFieldsValues(tuple)); | ||
| SWSS_LOG_DEBUG("%s", (dumpTuple(consumer, tuple)).c_str()); | ||
| } | ||
| /* | ||
| * Syncing from DB directly, don't expect duplicate keys. | ||
| * Or there is pending task from consumber state pipe, in this case just skip it. | ||
| */ | ||
| else | ||
| { | ||
| SWSS_LOG_WARN("Duplicate key %s found in tableName:%s\n", key.c_str(), tableName.c_str()); | ||
| continue; | ||
| } | ||
| doTask(consumer); | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| bool CfgOrch::execute(string tableName) | ||
| { | ||
| SWSS_LOG_ENTER(); | ||
|
|
||
| auto consumer_it = m_consumerMap.find(tableName); | ||
| if (consumer_it == m_consumerMap.end()) | ||
| { | ||
| SWSS_LOG_ERROR("Unrecognized tableName:%s\n", tableName.c_str()); | ||
| return false; | ||
| } | ||
| Consumer& consumer = consumer_it->second; | ||
|
|
||
| int data_popped = 0; | ||
| while (1) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
true
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, will change it. |
||
| { | ||
| KeyOpFieldsValuesTuple new_data; | ||
| consumer.m_consumer->pop(new_data); | ||
|
|
||
| string key = kfvKey(new_data); | ||
| string op = kfvOp(new_data); | ||
| /* | ||
| * Done with all new data. Or | ||
| * possible nothing popped, ie. the oparation is already merged with other operations | ||
| */ | ||
| if (op.empty()) | ||
| { | ||
| SWSS_LOG_DEBUG("Number of kfv data popped: %d\n", data_popped); | ||
| break; | ||
| } | ||
| data_popped++; | ||
| SWSS_LOG_DEBUG("%s", (dumpTuple(consumer, new_data)).c_str()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You could remove this pair.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. |
||
|
|
||
| /* If a new task comes or if a DEL task comes, we directly put it into consumer.m_toSync map */ | ||
| if (consumer.m_toSync.find(key) == consumer.m_toSync.end() || op == DEL_COMMAND) | ||
| { | ||
| consumer.m_toSync[key] = new_data; | ||
| } | ||
| /* If an old task is still there, we combine the old task with new task */ | ||
| else | ||
| { | ||
| KeyOpFieldsValuesTuple existing_data = consumer.m_toSync[key]; | ||
|
|
||
| auto new_values = kfvFieldsValues(new_data); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Many places, you could use "auto &" to reduce copying cost.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, will check how to sync with orch class too. |
||
| auto existing_values = kfvFieldsValues(existing_data); | ||
|
|
||
| for (auto it : new_values) | ||
| { | ||
| string field = fvField(it); | ||
| string value = fvValue(it); | ||
|
|
||
| auto iu = existing_values.begin(); | ||
| while (iu != existing_values.end()) | ||
| { | ||
| string ofield = fvField(*iu); | ||
| if (field == ofield) | ||
| iu = existing_values.erase(iu); | ||
| else | ||
| iu++; | ||
| } | ||
| existing_values.push_back(FieldValueTuple(field, value)); | ||
| } | ||
| consumer.m_toSync[key] = KeyOpFieldsValuesTuple(key, op, existing_values); | ||
| } | ||
| } | ||
| if (!consumer.m_toSync.empty()) | ||
| doTask(consumer); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| void CfgOrch::doTask() | ||
| { | ||
| for(auto &it : m_consumerMap) | ||
| { | ||
| if (!it.second.m_toSync.empty()) | ||
| doTask(it.second); | ||
| } | ||
| } | ||
|
|
||
| string CfgOrch::dumpTuple(Consumer &consumer, KeyOpFieldsValuesTuple &tuple) | ||
| { | ||
| string s = consumer.m_consumer->getTableName() + ":" + kfvKey(tuple) | ||
| + "|" + kfvOp(tuple); | ||
| for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++) | ||
| { | ||
| s += "|" + fvField(*i) + ":" + fvValue(*i); | ||
| } | ||
|
|
||
| return s; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| #pragma once | ||
|
|
||
| #include <map> | ||
| #include <memory> | ||
| #include "dbconnector.h" | ||
| #include "table.h" | ||
| #include "consumertable.h" | ||
|
|
||
| using namespace std; | ||
| using namespace swss; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. using namespace should not be used in header file.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, will remove them. |
||
|
|
||
| #define DEFAULT_KEY_SEPARATOR ":" | ||
| #define CONFIGDB_KEY_SEPARATOR "|" | ||
|
|
||
| typedef map<string, KeyOpFieldsValuesTuple> SyncMap; | ||
| struct Consumer { | ||
| Consumer(TableConsumable* consumer) : m_consumer(consumer) { } | ||
| TableConsumable* m_consumer; | ||
| /* Store the latest 'golden' status */ | ||
| SyncMap m_toSync; | ||
| }; | ||
| typedef pair<string, Consumer> ConsumerMapPair; | ||
| typedef map<string, Consumer> ConsumerMap; | ||
|
|
||
| class CfgOrch | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
inherit from Orch?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Orch looks too heavy for config orchestration, but cfgorch does have major overlap with orch. Will look into it further to see how to reduce the duplication. |
||
| { | ||
| public: | ||
| CfgOrch(DBConnector *db, string tableName); | ||
| CfgOrch(DBConnector *db, vector<string> &tableNames); | ||
| virtual ~CfgOrch(); | ||
|
|
||
| vector<Selectable*> getSelectables(); | ||
| bool hasSelectable(TableConsumable* s) const; | ||
|
|
||
| bool execute(string tableName); | ||
| /* Iterate all consumers in m_consumerMap and run doTask(Consumer) */ | ||
| void doTask(); | ||
|
|
||
| protected: | ||
| DBConnector *m_db; | ||
| ConsumerMap m_consumerMap; | ||
|
|
||
| /* Run doTask against a specific consumer */ | ||
| virtual void doTask(Consumer &consumer) = 0; | ||
| string dumpTuple(Consumer &consumer, KeyOpFieldsValuesTuple &tuple); | ||
| bool syncCfgDB(string tableName, Table &tableConsumer); | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ include /usr/share/dpkg/default.mk | |
|
|
||
| override_dh_auto_configure: | ||
| dh_auto_configure -- | ||
| dh_auto_configure -- --enable-gtest | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It will not work in sonic-slave. The tests require redis service running.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how sonic prepares unit test environment in Jenkins build. I install the debian package in sonic-slave and start redis service with "redis-server &" commond.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You got it clear. So just keep original version, and manually test it with |
||
|
|
||
| override_dh_auto_install: | ||
| dh_auto_install --destdir=debian/swss | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| CFLAGS_SAI = -I /usr/include/sai | ||
| INCLUDES = -I ../orchagent | ||
| INCLUDES = -I ../orchagent -I $(top_srcdir)/cfgorch | ||
|
|
||
| bin_PROGRAMS = tests | ||
|
|
||
|
|
@@ -9,12 +9,13 @@ else | |
| DBGFLAGS = -g -DNDEBUG | ||
| endif | ||
|
|
||
| CFLAGS_GTEST = | ||
| LDADD_GTEST = | ||
| CFLAGS_GTEST = -I $(top_srcdir)/../sonic-swss-common/googletest/googletest/include | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We should not refer any files outside the $(top_srcdir)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We only have google unit test environment in swss-common. What is your suggestion on how to build and run unit test in swss?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, the question is do we want to build unit test binary automatically like that in swss-common? Or it is ok just put unit test code there, whoever is interested in running the unit test can figure out how to build and run it themselves? The other option is to make gtest common library like swss-common.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree that we shall not include files outside this repository. I think the option 1 in the link Qi provided is preferred.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We plan to remove googletest from sonic-swss-common repo, and use installed Google Test DEB package near future. |
||
| LDADD_GTEST = $(top_srcdir)/../sonic-swss-common/googletest/build/googlemock/gtest/libgtest_main.a \ | ||
| $(top_srcdir)/../sonic-swss-common/googletest/build/googlemock/gtest/libgtest.a | ||
|
|
||
| tests_SOURCES = swssnet_ut.cpp | ||
| tests_SOURCES = swssnet_ut.cpp cfgorch_ut.cpp $(top_srcdir)/cfgorch/cfgorch.cpp | ||
|
|
||
| tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(CFLAGS_SAI) | ||
| tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(CFLAGS_SAI) | ||
| tests_LDADD = $(LDADD_GTEST) -lnl-genl-3 -lhiredis -lhiredis -lpthread \ | ||
| -lswsscommon -lswsscommon -lgtest -lgtest_main | ||
| -lswsscommon -lswsscommon | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use emplace to prevent object copy.