Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions common/configdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,30 @@ void ConfigDBConnector_Native::mod_config(const map<string, map<string, map<stri
}
}

// Write multiple tables into config db.
// Extra entries/fields in the db which are not in the data are kept.
// This version accepts an additional "order" parameter containing the table names
// to update in order.
void ConfigDBConnector_Native::mod_config(const unordered_map<string, map<string, map<string, string>>>& data,
const vector<string>& order)
{
for (auto const& table_name: order)
{
auto const& table_data_iter = data.find(table_name);
if (table_data_iter == data.end() || table_data_iter->second.empty() )
{
delete_table(table_name);
continue;
}
for (auto const& ie: table_data_iter->second)
{
string key = ie.first;
auto const& fvs = ie.second;
mod_entry(table_name, key, fvs);
}
}
}

// Read all config data.
// Returns:
// Config data in a dictionary form of
Expand Down Expand Up @@ -424,6 +448,35 @@ void ConfigDBPipeConnector_Native::mod_config(const map<string, map<string, map<
pipe.exec();
}

// Write multiple tables into config db.
// Extra entries/fields in the db which are not in the data are kept.
// This version accepts an additional "order" parameter containing the table names
// to update in order.
void ConfigDBPipeConnector_Native::mod_config(const unordered_map<string, map<string, map<string, string>>>& data,
const vector<string>& order)
{
auto& client = get_redis_client(m_db_name);
DBConnector clientPipe(client);
RedisTransactioner pipe(&clientPipe);
pipe.multi();
for (auto const& table_name: order)
{
auto const& table_data_iter = data.find(table_name);
if (table_data_iter == data.end() || table_data_iter->second.empty() )
{
_delete_table(client, pipe, table_name);
continue;
}
for (auto const& it: table_data_iter->second)
{
auto& key = it.first;
_mod_entry(pipe, table_name, key, it.second);
}
}
pipe.exec();
}


// Read config data in batches of size REDIS_SCAN_BATCH_SIZE using Redis pipelines
// Args:
// client: Redis client
Expand Down
6 changes: 5 additions & 1 deletion common/configdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class ConfigDBConnector_Native : public SonicV2Connector_Native
std::map<std::string, std::map<std::string, std::string>> get_table(std::string table);
void delete_table(std::string table);
virtual void mod_config(const std::map<std::string, std::map<std::string, std::map<std::string, std::string>>>& data);
virtual void mod_config(const std::unordered_map<std::string, std::map<std::string, std::map<std::string, std::string>>>& data,
const std::vector<std::string>& order);
virtual std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> get_config();

std::string getKeySeparator() const;
Expand Down Expand Up @@ -235,7 +237,7 @@ func NewConfigDBConnector(a ...interface{}) *ConfigDBConnector {
raw_key = self.serialize_key(key)
raw_data = self.typed_to_raw(data)
raw_config[table_name][raw_key] = raw_data
super(ConfigDBConnector, self).mod_config(raw_config)
super(ConfigDBConnector, self).mod_config(raw_config, list(raw_config))

def mod_entry(self, table, key, data):
key = self.serialize_key(key)
Expand Down Expand Up @@ -331,6 +333,8 @@ class ConfigDBPipeConnector_Native: public ConfigDBConnector_Native

void set_entry(std::string table, std::string key, const std::map<std::string, std::string>& data) override;
void mod_config(const std::map<std::string, std::map<std::string, std::map<std::string, std::string>>>& data) override;
void mod_config(const std::unordered_map<std::string, std::map<std::string, std::map<std::string, std::string>>>& data,
const std::vector<std::string>& order) override;
std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> get_config() override;

private:
Expand Down
4 changes: 4 additions & 0 deletions pyext/swsscommon.i
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
%include <std_map.i>
%include <std_deque.i>
#ifdef SWIGPYTHON
%include <std_unordered_map.i>
%include <std_shared_ptr.i>
#endif
%include <typemaps.i>
Expand All @@ -81,6 +82,9 @@
%template(ScanResult) std::pair<int64_t, std::vector<std::string>>;
%template(GetTableResult) std::map<std::string, std::map<std::string, std::string>>;
%template(GetConfigResult) std::map<std::string, std::map<std::string, std::map<std::string, std::string>>>;
#ifdef SWIGPYTHON
%template(GetUnorderedConfigResult) std::unordered_map<std::string, std::map<std::string, std::map<std::string, std::string>>>;
#endif
%template(GetInstanceListResult) std::map<std::string, swss::RedisInstInfo>;
%template(KeyOpFieldsValuesQueue) std::deque<std::tuple<std::string, std::string, std::vector<std::pair<std::string, std::string>>>>;
%template(VectorSonicDbKey) std::vector<swss::SonicDBKey>;
Expand Down
59 changes: 58 additions & 1 deletion tests/test_redis_ut.py
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,64 @@ def test_ConfigDBConnector_with_statement(self):
# check close() method called by with statement
ConfigDBConnector.close.assert_called_once_with()

def _test_ConfigDBConnectorSetOrder(cls):
table_name_1 = "PREFIX_SET"
table_name_2 = "PREFIX"
inp = {
table_name_1: {
"test_prefix_set": {
"mode": "IPv4"
}
},
table_name_2: {
"test_prefix_set|10.1.0.0/24|exact": {
"action": "permit"
}
}
}

ret_queue = multiprocessing.Queue()

def thread_listen(ret_queue):
config_db = ConfigDBConnector()
config_db.connect(wait_for_init=False)

def handler(table, key, data):
print('thread_listen received', table, key, data)
ret_queue.put(table)

config_db.subscribe(table_name_1, handler)
config_db.subscribe(table_name_2, handler)
config_db.listen()

config_db = cls()
config_db.connect(wait_for_init=False)
client = config_db.get_redis_client(config_db.CONFIG_DB)
client.flushdb()

listener = multiprocessing.Process(target=thread_listen, args=(ret_queue,))
listener.start()

# Wait until the listener has connected before modifying the config
time.sleep(2)

try:
config_db.mod_config(inp)
# Check that items are added to the queue in order
assert ret_queue.get(timeout=5) == table_name_1
assert ret_queue.get(timeout=5) == table_name_2
finally:
listener.terminate()

def test_ConfigDBConnectorSetOrder():
"""Check that ConfigDBConnector::mod_config updates tables in order of the
input Python dict"""
_test_ConfigDBConnectorSetOrder(ConfigDBConnector)

def test_ConfigDBPipeConnectorSetOrder():
"""Check that ConfigDBPipeConnector::mod_config updates tables in order of the
input Python dict"""
_test_ConfigDBConnectorSetOrder(ConfigDBPipeConnector)

def test_SmartSwitchDBConnector():
test_dir = os.path.dirname(os.path.abspath(__file__))
Expand Down Expand Up @@ -878,4 +936,3 @@ def test_TableOpsMemoryLeak():
t.set("long_data", fvs)
t.get("long_data")
assert psutil.Process(os.getpid()).memory_info().rss - rss < OP_COUNT

Loading